package cn.buk.qms.service;

import cn.buk.api.azure.BlobService;
import cn.buk.api.azure.BlobServiceImpl;
import cn.buk.api.wechat.dto.BaseResponse;
import cn.buk.api.wechat.entity.WeixinEntConfig;
import cn.buk.api.wechat.entity.WeixinServiceConfig;
import cn.buk.api.wechat.work.dto.*;
import cn.buk.api.wechat.work.service.WorkWeixinService;
import cn.buk.common.JsonResult;
import cn.buk.common.dto.CommonDto;
import cn.buk.common.sc.CommonSearchCriteria;
import cn.buk.qms.OrderUtil;
import cn.buk.tms.dao.FlightOrderDao;
import cn.buk.tms.dto.SupplierDto;
import cn.buk.tms.dto.*;
import cn.buk.tms.entity.config.EtermEntConfig;
import cn.buk.tms.entity.order.OrderNoInfo;
import cn.buk.tms.sc.SearchCustomerCriteria;
import cn.buk.tms.sc.SearchFlightOrderCriteria;
import cn.buk.tms.admin.EntAlipayCfgDto;
import cn.buk.tms.common.constant.TmsConstant;
import cn.buk.tms.common.constant.TmsOrderConstant;
import cn.buk.tms.common.dto.*;
import cn.buk.tms.dto.CustomerFlightDiscountDto;
import cn.buk.tms.entity.base.Airline;
import cn.buk.tms.entity.base.Airport;
import cn.buk.tms.entity.misc.*;
import cn.buk.tms.entity.order.flight.FlightOrder;
import cn.buk.tms.entity.order.flight.FlightOrderPassenger;
import cn.buk.tms.flight.dao.KeyCustomerPolicyDao;
import cn.buk.tms.flight.dto.AirlinesTgqInfo;
import cn.buk.tms.flight.dto.KeyCustomerPolicyDto;
import cn.buk.tms.util.ValidationUtils;
import cn.buk.common.util.CheckUtil;
import cn.buk.common.util.DateUtil;
import cn.buk.common.util.StringUtil;
import cn.buk.common.util.VerifyCodeUtil;
import com.alibaba.fastjson.JSON;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Component;

import jakarta.transaction.Transactional;
import jakarta.validation.constraints.NotNull;
import java.io.File;
import java.io.FileInputStream;
import java.text.ParseException;
import java.util.*;

import static cn.buk.common.Constant.DATE_YYYY_MM_DD;
import static cn.buk.tms.entity.misc.Customer.ENT_CORPORATION;
import static cn.buk.tms.entity.config.EnterpriseConfig.*;
import static cn.buk.tms.entity.misc.TmsTask.TMS_TASK_TYPE_DAILY_AUDIT;
import static cn.buk.tms.common.constant.TmsConstant.*;
import static java.util.stream.Collectors.toList;

/**
 * @author yfdai
 */
@Component
public class EnterpriseServiceImpl extends BaseAbstractService implements EnterpriseService {

  private static final Logger logger = LogManager.getLogger(EnterpriseServiceImpl.class);

  @Autowired
  private UserService userService;

  @Autowired
  private WorkWeixinService wwService;

  @Autowired
  private FlightOrderDao flightOrderDao;

  @Autowired
  private KeyCustomerPolicyDao keyCustomerPolicyDao;

  @Override
  public Enterprise getEnterpriseById(int enterpriseId) {
    return enterpriseDao.getEnterpriseById(enterpriseId);
  }



  /**
   * 查找的企业客户的授信信息
   *
   */
  @Override
  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER})
  public List<EntBalanceDto> searchCustomerBalances(final int enterpriseId, SearchCustomerCriteria sc) {

    List<EnterpriseBalance> balances = enterpriseDao.searchMyEntBalance(enterpriseId);
    List<Customer> customers = customerDao.searchCustomers(enterpriseId, sc, null);

    List<EntBalanceDto> dtos = new ArrayList<>();
    for (Customer c : customers) {
      for (EnterpriseBalance balance : balances) {
        if (c.getCustomerEnterpriseId() == (balance.getEnterpriseId())) {
          EntBalanceDto dto = new EntBalanceDto();
          BeanUtils.copyProperties(balance, dto);

          dto.setName(c.getVipName());
          dto.setPinyin(c.getPinyin());
          dto.setCustomerCode(c.getCustomerCode());
          dtos.add(dto);
          break;
        }
      }
    }

    return dtos;
  }

  /**
   * 平台管理操作: 调整客户资金账户余额
   */
  @Override
  public JsonResult updateEntCashBalance(int enterpriseId, int objectEnterpriseId, int opMode, int modifyAmount, String remark) {
    JsonResult jsonResult = new JsonResult();
    jsonResult.setStatus("ER");

    if (modifyAmount == 0 || remark == null || remark.trim().length() == 0) {
      jsonResult.setErrmsg("金额和原因必填");
    } else {
      int retCode;
      if (enterpriseId != Enterprise.ENTERPRISE_PLATFORM_ADMINISTRATOR) {
        retCode = enterpriseDao.updateMyEntCashBalance(enterpriseId, objectEnterpriseId, opMode, modifyAmount, remark);
      } else {
        retCode = enterpriseDao.updateEntCashBalance(objectEnterpriseId, opMode, modifyAmount, remark);
      }
      if (retCode > 0) {
        jsonResult.setStatus("OK");
      } else {
        jsonResult.setErrcode(retCode);
      }
    }

    return jsonResult;
  }

  @Override
  public JsonResult buyPoints(int enterpriseId) {
    JsonResult jsonResult = new JsonResult();
    jsonResult.setStatus("OK");

    try {
      int retCode = enterpriseDao.buyPoints(enterpriseId);
      if (retCode > 0) {
        jsonResult.setDesc("购买了 " + retCode + "积分");
      } else if (retCode == -4) {
        jsonResult.setStatus("ER");
        jsonResult.setErrmsg("无法购买积分");
      } else {
        jsonResult.setErrmsg("出错了");
      }
    } catch (Exception ex) {
      jsonResult.setStatus("ER");
      jsonResult.setErrmsg(ex.getMessage());
    }

    return jsonResult;
  }

  @Override
  public JsonResult createEntCreditLimit(int enterpriseId, int authorizee, int creditLimit) {
    JsonResult jsonResult = new JsonResult();
    jsonResult.setStatus("ER");

    if (authorizee < 1) {
      jsonResult.setErrmsg("请选择需要授权的客户");
    } else {
      int retCode = enterpriseDao.createEntCreditLimit(enterpriseId, authorizee, creditLimit);
      if (retCode > 0) {
        jsonResult.setStatus("OK");
      } else {
        jsonResult.setErrmsg("保存失败");
      }
    }

    return jsonResult;
  }

  @Override
  public List<PassengerDto> searchPsgInfo(int enterpriseId, int userId, SearchCustomerCriteria sc) {
    List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);

    List<Passenger> passengers = passengerDao.searchPsgInfo(enterpriseId, sc, allowedCustomerIds);

    List<PassengerDto> dtos = new ArrayList<>();

    final boolean needHideCustomerName = isNeedHideCustomerName(enterpriseId, userId);

    for (Passenger passenger : passengers) {
      maskCustomerName(passenger.getCustomer(), null, null, needHideCustomerName);

      PassengerDto dto = PassengerDto.createBy(passenger);

      dtos.add(dto);
    }

    return dtos;
  }

  @Override
  public PassengerDto getPassengerInfo(int enterpriseId, int id) {
    Passenger passenger = enterpriseDao.getPassengerById(enterpriseId, id);
    if (passenger == null) {
      return null;
    }

    PassengerDto psgDto = PassengerDto.createBy(passenger);

    //查找该乘机人适用的机票政策
    List<PassengerFlightPolicy> flightPolicies = enterpriseDao.searchPassengerFlightPolicies(enterpriseId, id);
    for(PassengerFlightPolicy flightPolicy: flightPolicies) {
      KeyCustomerPolicyDto dto = new KeyCustomerPolicyDto();
      BeanUtils.copyProperties(flightPolicy.getPolicyInfo(), dto);

      psgDto.getFlightPolicies().add(dto);
    }

    return psgDto;
  }


  /**
   * 保存/修改 企业员工信息
   *
   */
  @Override
  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_DATA_ADMIN})
  public JsonResult savePsgInfo(int enterpriseId, int userId, String username, PassengerDto dto) {
    if (dto == null || dto.getNameCn().length() < 2) {
      return JsonResult.createJsonResult(-1, "乘机人的中文名不能为空");
    }

    JsonResult jsonResult = new JsonResult();
    jsonResult.setStatus("ER");

    int status;

    try {
      Passenger passenger = PassengerDto.convertTo(dto, enterpriseId);

      status = passengerDao.savePsgInfo(passenger);

      return JsonResult.createJsonResult(status);
    } catch (Exception ex) {
      logger.error(ex.getMessage());
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Override
  public List<CustomerDepartmentDto> searchCustomerDepartments(final int enterpriseId, SearchCustomerCriteria sc) {
    //TODO yfdai 2021-03-25 当前用户允许查看哪些客户的部门信息
    List<CustomerDepartment> list = enterpriseDao.searchCustomerDepartments(enterpriseId, sc);

    List<CustomerDepartmentDto> dtos = new ArrayList<>();
    for(CustomerDepartment o: list) {
      dtos.add(getCustomerDepartmentDto(o));


    }

    return dtos;
  }

  @Override
  public JsonResult saveCustomerDepartment(final int enterpriseId, final int userId, CustomerDepartment department) {
    if (department == null || department.getName() == null || department.getName().length() < 2) {
      return JsonResult.createJsonResult(-1, "部门名称是必需的");
    }

    if (department.getDepartmentNo() == null || department.getDepartmentNo() < 1) {
      return JsonResult.createJsonResult(-2, "部门ID是必需的");
    }

    if (department.getCustomer() == null || department.getCustomer().getId() == 0) {
      return JsonResult.createJsonResult(-1, "所属企业是必需选择的");
    }

    //校验上级部门是否存在
    if (department.getParentDepartmentNo() > 0) {
      CustomerDepartment p = enterpriseDao.getCustomerDepartmentByDeptId(enterpriseId, department.getCustomer().getId(), department.getParentDepartmentNo());
      if (p == null) {
        return JsonResult.createJsonResult(-1, "上级部门不存在");
      }
      department.setLevel(p.getLevel() + 1);
    }

    if (department.getLevel() > 2) {
      return JsonResult.createJsonResult(-1, "目前只支持三级部门");
    }

    JsonResult jsonResult = new JsonResult();
    jsonResult.setStatus("ER");

    User user = userDao.getUserById(userId);

    try {
      int status = enterpriseDao.saveCustomerDepartment(enterpriseId, user.getUsername(), department);
      if (status > 0) {
        jsonResult.setStatus("OK");
      } else {
        jsonResult.setErrcode(status);
      }

      return jsonResult;
    } catch (Exception ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }



  /**
   * 获取携程联盟的站点id
   *
   */
  @Override
  public String getCtripAllianceSiteId(int enterpriseId) {
    String sid = doGetEntCfg(enterpriseId, CTRIP_ALLIANCE_SITE_ID);

    if (sid == null || sid.trim().length() == 0) {
      sid = "458559";
    }

    return sid;
  }

  @Override
  public String getRedmineUrl(int enterpriseId) {
    return doGetEntCfg(enterpriseId, REDMINE_URL);
  }

  /**
   * 查找供应商
   *
   */
  @Override
  public List<SupplierDto> searchSuppliers(final int enterpriseId, CommonSearchCriteria sc) {
    List<Supplier> suppliers = enterpriseDao.searchSuppliers(enterpriseId, sc);

    List<SupplierDto> dtos = new ArrayList<>();
    for (Supplier supplier : suppliers) {
      SupplierDto dto = new SupplierDto();
      BeanUtils.copyProperties(supplier, dto);

      if (dto.getPaymentMethodId() > 0) {
        PaymentMethod pm = enterpriseDao.getPaymentMethodById(enterpriseId, dto.getPaymentMethodId());
        if (pm != null) {
          dto.setPaymentMethodName(pm.getName());
        }
      }

      dtos.add(dto);
    }

    return dtos;
  }

  @Override
  public SupplierDto searchSupplier(int enterpriseId, int id) {
    Supplier supplier = enterpriseDao.getSupplierById(enterpriseId, id);
    if (supplier == null) {
      return null;
    }

    SupplierDto dto = new SupplierDto();
    BeanUtils.copyProperties(supplier, dto);

    if (dto.getPaymentMethodId() > 0) {
      PaymentMethod pm = enterpriseDao.getPaymentMethodById(enterpriseId, dto.getPaymentMethodId());
      if (pm != null) {
        dto.setPaymentMethodName(pm.getName());
      }
    }

    return dto;
  }

  /**
   * 创建或修改供应商
   *
   */
  @Override
  @Secured(RoleInfo.ROLE_ADMIN)
  public JsonResult createSupplier(final int enterpriseId, final String username, final Supplier info) {
    if (info.getName() == null || info.getName().trim().length() == 0) {
      return JsonResult.createJsonResult(-1, "名字必需填写。");
    }
    int retCode;
    String errmsg = null;

    try {
      if (info.getId() == 0) {
        retCode = enterpriseDao.createSupplier(enterpriseId, info);
      } else {
        retCode = enterpriseDao.updateSupplier(enterpriseId, info);
      }
    } catch (Exception ex) {
      ex.printStackTrace();
      errmsg = ex.getMessage();
      retCode = -100;
    }

    return JsonResult.createJsonResult(retCode, errmsg);
  }

  /**
   * 查找支出支付方式
   *
   */
  @Override
  public List<PaymentMethodDto> searchPaymentMethods(int enterpriseId, CommonSearchCriteria sc) {
    List<PaymentMethod> datas = enterpriseDao.searchPaymentMethods(enterpriseId, sc);

    List<PaymentMethodDto> dtos = new ArrayList<>();
    for (PaymentMethod info : datas) {
      PaymentMethodDto dto = new PaymentMethodDto();
      BeanUtils.copyProperties(info, dto);

      dtos.add(dto);
    }

    return dtos;
  }

  @Override
  public List<IncomeMethodDto> searchIncomeMethods(int enterpriseId, CommonSearchCriteria sc) {
    List<IncomeMethod> datas = enterpriseDao.searchIncomeMethods(enterpriseId, sc);

    List<IncomeMethodDto> dtos = new ArrayList<>();
    for (IncomeMethod info : datas) {
      IncomeMethodDto dto = new IncomeMethodDto();
      BeanUtils.copyProperties(info, dto);

      dtos.add(dto);
    }

    return dtos;
  }

  /**
   * 新建支付方式
   *
   */
  @Override
  public JsonResult createPaymentMethod(final int enterpriseId, final PaymentMethod info) {
    if (info.getName() == null || info.getName().trim().length() == 0) {
      return JsonResult.createJsonResult(-1, "名字必需填写");
    }

    if (info.getPinyin() != null) {
      info.setPinyin(info.getPinyin().trim().toUpperCase());
    }

    int retCode;

    try {
      if (info.getId() == 0) {
        retCode = enterpriseDao.createPaymentMethod(enterpriseId, info);
      } else {
        retCode = enterpriseDao.updatePaymentMethod(enterpriseId, info);
      }
    } catch (Exception ex) {
      ex.printStackTrace();
      retCode = -100;
    }
    return JsonResult.createJsonResult(retCode);
  }

  @Override
  public JsonResult createIncomeMethod(int enterpriseId, IncomeMethod o) {
    if (o.getName() == null || o.getName().trim().length() == 0) {
      return JsonResult.createJsonResult(-1, "名字必需填写");
    }
    int retCode;
    if (o.getId() == 0) {
      retCode = enterpriseDao.createIncomeMethod(enterpriseId, o);
    } else {
      retCode = enterpriseDao.updateIncomeMethod(enterpriseId, o);
    }
    return JsonResult.createJsonResult(retCode);
  }

  @Override
  public List<CustomerDepartment> searchDepartmentsByCustomer(int enterpriseId, int customerId) {
    return enterpriseDao.searchDepartmentsByCustomer(enterpriseId, customerId);
  }

  @Override
  @Secured(RoleInfo.ROLE_ADMIN)
  public List<GroupDto> searchGroups(int enterpriseId, CommonSearchCriteria sc) {
    List<Groups> list0 = enterpriseDao.searchGroups(enterpriseId, sc);

    List<GroupDto> list1 = new ArrayList<>();

    for (Groups info : list0) {
      for (GroupRole o : info.getAuthorities()) {
        o.setGroupInfo(null);
      }

      for (GroupUsers o : info.getUsers()) {
        o.setGroupInfo(null);
      }

      GroupDto dto = new GroupDto();
      list1.add(dto);

      BeanUtils.copyProperties(info, dto);
    }

    //角色名称
    List<RoleInfo> roleInfos = enterpriseDao.searchRoles(enterpriseId);
    for(GroupDto d: list1) {
      for(GroupRole gr: d.getAuthorities()) {
        if (gr.getRole() != null && gr.getRole().trim().length() > 0) {
          for (RoleInfo roleInfo : roleInfos) {
            if (roleInfo.getRole().equalsIgnoreCase(gr.getRole())) {
              gr.setRoleName(roleInfo.getRoleName());
              break;
            }
          }
        }
      }
    }

    return list1;
  }

  @Override
  public JsonResult createGroup(int enterpriseId, int userId, String groupName) {
    Groups o = new Groups();
    o.setEnterpriseId(enterpriseId);
    o.setGroupName(groupName);

    return JsonResult.createJsonResult(enterpriseDao.createGroup(o));
  }

  /**
   * 修改组包含的角色
   */
  @Override
  @Secured(RoleInfo.ROLE_ADMIN)
  public JsonResult updateGroupRole(final int enterpriseId, final int userId, int groupId, String roleName) {
    // 判断操作的组里面是否有ROLE_ADMIN
    boolean hasRoleAdmin = hasRoleAdminPrivilege(enterpriseId, userId, groupId);
    if (!hasRoleAdmin) {
      //不是根管理员，不能在组中增加管理员角色
      return JsonResult.createJsonResult(-1, "您无权限操作管理员角色");
    }

    // 判断新增加的角色里是否有ROLE_ADMIN
    String[] roles = roleName.trim().toUpperCase().split(",");
    hasRoleAdmin = false;
    for (String role : roles) {
      if (role.equalsIgnoreCase(RoleInfo.ROLE_ADMIN)) {
        hasRoleAdmin = true;
        break;
      }
    }
    if (hasRoleAdmin && enterpriseId != userId) {
      //不是根管理员，不能在组中增加管理员角色
      return JsonResult.createJsonResult(-1, "您无权限操作管理员角色");
    }

    int retCode = enterpriseDao.updateGroupRole(enterpriseId, groupId, roles);

    return JsonResult.createJsonResult(retCode);
  }

  /**
   * 向组中添加用户
   */
  @Override
  @Secured(RoleInfo.ROLE_ADMIN)
  public JsonResult addUserToGroup(int enterpriseId, int userId, int paramUserId, int groupId) {

    Groups groupInfo = enterpriseDao.getGroupInfoById(groupId);
    if (groupInfo == null || groupInfo.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-1, "数据错误");
    }

    boolean hasRoleAdmin = hasRoleAdminPrivilege(enterpriseId, userId, groupId);
    if (!hasRoleAdmin) {
      //不是根管理员，不能在组中增加管理员角色
      return JsonResult.createJsonResult(-1, "您无权限操作管理员角色");
    }

    int retCode = enterpriseDao.addUserToGroup(groupId, paramUserId);

    return JsonResult.createJsonResult(retCode);
  }

  @Override
  @Secured(RoleInfo.ROLE_ADMIN)
  public JsonResult deleteUserFromGroup(int enterpriseId, int userId, int paramUserId, int groupId) {
    Groups groupInfo = enterpriseDao.getGroupInfoById(groupId);
    if (groupInfo == null || groupInfo.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-1, "数据错误");
    }

    boolean hasRoleAdmin = hasRoleAdminPrivilege(enterpriseId, userId, groupId);
    if (!hasRoleAdmin) {
      //不是根管理员，不能在组中增加管理员角色
      return JsonResult.createJsonResult(-1, "您无权限操作管理员角色");
    }

    int retCode = enterpriseDao.deleteUserFromGroup(groupId, paramUserId);
    return JsonResult.createJsonResult(retCode);
  }

  /**
   * 是否有操作ROLE_ADMIN的权限
   */
  private boolean hasRoleAdminPrivilege(int enterpriseId, int userId, int groupId) {
    Groups groupInfo = enterpriseDao.getGroupInfoById(groupId);

    var hasRoleAdmin = false;
    for (GroupRole role : groupInfo.getAuthorities()) {
      if (RoleInfo.ROLE_ADMIN.equalsIgnoreCase(role.getRole())) {
        hasRoleAdmin = true;
        break;
      }
    }
    return !hasRoleAdmin || enterpriseId == userId;
  }

  @Override
  public List<RoleInfo> searchRoles(int enterpriseId) {
    return enterpriseDao.searchRoles(enterpriseId);
  }

  /**
   * 查找角色对应的权限
   */
  @Override
  public CommonDto<RolePrivilege> searchRolePrivileges(int enterpriseId, CommonSearchCriteria sc) {
    List<RolePrivilege> privileges = enterpriseDao.searchRolePrivileges(enterpriseId, sc);

    CommonDto<RolePrivilege> commonDto = new CommonDto<>();
    commonDto.setDataList(privileges);
    commonDto.setPage(sc.getPage());

    return commonDto;
  }

  @Override
  public JsonResult deleteRolePrivilege(int enterpriseId, int id) {
    int retCode = enterpriseDao.deleteRolePrivilege(enterpriseId, id);
    return JsonResult.createJsonResult(retCode);
  }

  @Override
  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_DATA_ADMIN})
  public JsonResult addRolePrivilege(int enterpriseId, String role, Integer[] privilegeIds) {
    int retCode = enterpriseDao.addRolePrivilege(enterpriseId, role, privilegeIds);
    return JsonResult.createJsonResult(retCode);
  }

  @Override
  public List<SysPrivilege> searchPrivileges(int enterpriseId) {
    return enterpriseDao.searchPrivileges(enterpriseId);
  }

  @Override
  public List<CustomerNote> searchCustomerNotes(int enterpriseId, CommonSearchCriteria sc, final int customerId, final int noteType) {
    return enterpriseDao.searchCustomerNotes(enterpriseId, sc, customerId, noteType);
  }

  @Override
  public JsonResult createCustomerNote(int enterpriseId, int customerId, int noteType, String name) {
    try {
      return JsonResult.createJsonResult(
          enterpriseDao.createCustomerNote(enterpriseId, customerId, noteType, name));
    } catch (RuntimeException ex) {
      ex.printStackTrace();
      String msg = ex.getMessage();
      if (msg.contains("org.hibernate.exception.ConstraintViolationException")) {
        msg = "请检查 数据 是否重复？";
      }
      return JsonResult.createJsonResult(-100, msg);
    }
  }

  @Override
  public List<CustomerNote> searchCustomerNotesByType(int enterpriseId, int customerId, int noteType) {
    return enterpriseDao.searchCustomerNotesByType(enterpriseId, customerId, noteType);
  }

  @Override
  public JsonResult deleteCustomerNoteById(int enterpriseId, int id) {
    return JsonResult.createJsonResult(enterpriseDao.deleteCustomerNoteById(enterpriseId, id));
  }


  @Override
  public List<AirlinesDto> searchAirlines(final int enterpriseId, CommonSearchCriteria sc) {
    List<Airline> airlinesList = basicDataDao.searchAirlines(sc);

    List<AirlinesDto> dtos = new ArrayList<>();
    for(Airline info: airlinesList) {
      dtos.add(AirlinesDto.createBy(info));
    }

    return dtos;
  }

  @Override
  public CommonDto<FakeTicketNo> searchFakedTickets(int enterpriseId, CommonSearchCriteria sc) {
    List<FakeTicketNo> dataList = enterpriseDao.searchFakedTickets(enterpriseId, sc);

    CommonDto<FakeTicketNo> commonDto = new CommonDto<>();
    commonDto.setDataList(dataList);
    commonDto.setPage(sc.getPage());

    return commonDto;
  }

  @Override
  @Secured(RoleInfo.ROLE_ADMIN)
  public JsonResult createFakedTicket(int enterpriseId, String twoCode) {
    List<Airline> airlines = basicDataDao.searchAirlines(twoCode);
    if (airlines.isEmpty()) {
      return JsonResult.createJsonResult(-1, "未在航空公司基础信息中找到此两字代码的资料，请先录入航空公司基础信息");
    }

    Airline airline = airlines.get(0);
    FakeTicketNo f = new FakeTicketNo();
    f.setEnterpriseId(enterpriseId);
    f.setTwoCode(airline.getTwoCode());
    f.setThreeCode(airline.getThreeCode());

    return JsonResult.createJsonResult(enterpriseDao.createFakedTicket(f));
  }

  @Override
  public CommonDto<EntDepartment> searchEntDepartments(int enterpriseId, CommonSearchCriteria sc) {
    List<EntDepartment> departments = enterpriseDao.searchEntDepartments(enterpriseId, sc);

    if (departments.isEmpty()) {
      JsonResult jsonResult = this.syncEntDepartments(enterpriseId);
      if ("OK".equalsIgnoreCase(jsonResult.getStatus())) {
        departments = enterpriseDao.searchEntDepartments(enterpriseId, sc);
      }
    }

    //角色
    List<RoleInfo> roleInfos = enterpriseDao.searchRoles(enterpriseId);
    for(EntDepartment d: departments) {
      if (d.getRole() != null && d.getRole().trim().length() > 0) {
        for(RoleInfo roleInfo: roleInfos) {
          if (roleInfo.getRole().equalsIgnoreCase(d.getRole())) {
            d.setRoleName(roleInfo.getRoleName());
            break;
          }
        }
      }
    }

    CommonDto<EntDepartment> commonDto = new CommonDto<>();
    commonDto.setDataList(departments);
    commonDto.setPage(sc.getPage());

    return commonDto;
  }

  /**
   * 创建/修改企业微信的部门
   *
   * @param enterpriseId 企业id
   * @param username     用户名
   * @param id           本系统的部门id
   * @param name         部门名称
   * @param role 部门的默认角色
   * @param parentId     企业微信的上级部门id
   * @param wwDeptId     企业微信的部门id
   * @param remark       备注
   * @return JsonResult
   */
  @Override
  public JsonResult createDepartment(final int enterpriseId, final String username, final int id,
      final String name, final String role, final int parentId, final int wwDeptId, final String remark) {
    EntDepartment department = null;
    if (id > 0) {
      department = enterpriseDao.getEntDepartment(id);
      if (department == null || department.getEnterpriseId() != enterpriseId) {
        return JsonResult.createJsonResult(-1, "不存在此部门");
      }
    }

    WwDepartment dept = new WwDepartment();
    dept.setName(name);
    dept.setParentid(parentId);
    dept.setId(wwDeptId);

    int newWwDeptId = wwDeptId;

    int errCode;
    String errmsg = null;
    try {
      if (id == 0) {
        //创建新部门
        CreateDepartmentResponse rs = workWeixinService.createDepartment(enterpriseId, dept);
        errCode = rs.getErrcode();
        if (errCode != 0) {
          logger.warn("{}: {}.", rs.getErrcode(), rs.getErrmsg());
        } else {
          newWwDeptId = rs.getId();
        }
      } else {
        BaseResponse rs = workWeixinService.updateDepartment(enterpriseId, dept);
        errCode = rs.getErrcode();
        if (errCode != 0) {
          logger.warn("{}: {}.", rs.getErrcode(), rs.getErrmsg());
        }
      }
    } catch (Exception ex) {
      errmsg = ex.getMessage();
      ex.printStackTrace();
    }

    // 本地也保存
    if (department == null) {
      department = new EntDepartment();
    }
    department.setName(name);
    department.setRole(role);
    department.setParentId(parentId);
    department.setDeptId(newWwDeptId);
    department.setRemark(remark);

    try {
      int retCode = enterpriseDao.saveEntDepartment(department);

      return JsonResult.createJsonResult(retCode, errmsg);
    } catch (Exception ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  /**
   * 删除部门：先删除企业微信的，再删除本地的
   */
  @Override
  public JsonResult deleteDepartment(final int enterpriseId, String username, final int id) {
    EntDepartment department = enterpriseDao.getEntDepartment(id);

    if (department == null || department.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-1, "不存在此部门");
    }

    try {
      BaseResponse rs = workWeixinService.deleteDepartment(enterpriseId, department.getDeptId());
      if (rs.getErrcode() == 0 || rs.getErrcode() == 60123) {
        //删除成功 或 60123无效的部门id
        try {
          int retCode = enterpriseDao.deleteEntDepartment(enterpriseId, id);
          return JsonResult.createJsonResult(retCode);
        } catch (RuntimeException ex) {
          return JsonResult.createJsonResult(-100, "远端删除成功，本地删除失败(" + ex.getMessage() + ")");
        }
      } else if (rs.getErrcode() == 60005) {
        if (department.getDeptId() == 1) {
          //根部门
          List<EntDepartment> departments = enterpriseDao.searchEntDepartmentByWwDeptId(enterpriseId, 1);
          if (departments.size() > 1) {
            int retCode = enterpriseDao.deleteEntDepartment(enterpriseId, id);
            return JsonResult.createJsonResult(retCode);
          }
        }
        return JsonResult.createJsonResult(-2, "部门里存在成员");
      } else if (rs.getErrcode() == 60006) {
        return JsonResult.createJsonResult(-3, "存在下级部门");
      } else {
        return JsonResult.createJsonResult(-99, rs.getErrcode() + ": " + rs.getErrmsg());
      }
    } catch (Exception ex) {
      return JsonResult.createJsonResult(-101, ex.getMessage());
    }
  }

  /**
   * 创建或修改企业微信的用户信息
   *
   */
  @Override
  public void createOrUpdateWwUser(final int enterpriseId, final String username0, final String name,
      final String email, final String mobileNo, final String etermUsername, final String position) {
    User user = userDao.getUserByUsername(username0);
    if (user == null) {
      return;
    }

    final String username = user.getWwUserId().length() == 0 ? username0 : user.getWwUserId();

    int[] depts;
    final int size = user.getDepartments().size();
    if (size == 0) {
      depts = new int[1];
      depts[0] = 1;
    } else {
      depts = new int[size];
      for (int i = 0; i < size; i++) {
        depts[i] = user.getDepartments().get(i).getDeptId();
      }
    }

    Runnable r = () -> {
      BaseResponse rs;

      WwUser u = workWeixinService.getUser(enterpriseId, username);
      if (u.getErrcode() == 0) {
        // 已存在该userId
        if (user.getStatus() == User.USER_STATUS_NORMAL) {
          u.setEnable(1);
        } else {
          u.setEnable(0);
        }
      } else {
        u = new WwUser();
        u.setErrcode(-1);
        u.setUserid(username);
        u.setEnable(1);
      }

      u.setName(name);
      u.setEmail(email);
      u.setMobile(mobileNo);
      u.setDepartment(depts);
      u.setPosition(position);
      u.setIsLeader(null);

      if (etermUsername != null && etermUsername.trim().length() > 0) {
        BaseAttr baseAttr = new BaseAttr();
        baseAttr.setName("eterm-id");
        baseAttr.setValue(etermUsername);
        u.getExtattr().getAttrs().add(baseAttr);
      }

      if (u.getErrcode() == 0) {
        rs = workWeixinService.updateUser(enterpriseId, u);
      } else {
        rs = workWeixinService.createUser(enterpriseId, u);
      }

      if (rs.getErrcode() == 0) {
        // 修改或新增企业微信id成功
        if (user.getWwUserId().length() == 0) {
          userDao.updateWwUserId(enterpriseId, user.getId(), username);
        }
      } else {
        logger.error("{}: {}.", rs.getErrcode(), rs.getErrmsg());
        //TODO: 记录到哪里？怎么发通知？
      }
    };

    threadPool.execute(r);

  }

  @Override
  public EntDepartment getEntDepartmentById(int enterpriseId, int id) {
    EntDepartment department = enterpriseDao.getEntDepartment(id);
    if (department == null || department.getEnterpriseId() != enterpriseId) {
      return null;
    } else {
      return department;
    }
  }

  /**
   * 企业微信的二次验证
   */
  @Override
  public JsonResult validateWwUser(User u, String wwCode, String remoteAddress) {
    UserInfoResponse rs = workWeixinService.getUserInfo(u.getEnterpriseId(), wwCode);
    if (rs != null && rs.getErrcode() == 0 && rs.getUserId() != null && rs.getUserId().trim().length() > 0) {
      // 二次验证成功
      int retCode = userDao.updateWwUserId(u.getEnterpriseId(), u.getId(), rs.getUserId());
      if (retCode == 1) {
        BaseResponse rs0 = workWeixinService.authUserSuccessfully(u.getEnterpriseId(), rs.getUserId());
        if (rs0.getErrcode() == 0) {
          return JsonResult.createJsonResult(1, "企业微信二次验证成功，当前账号已与企业用户绑定！");
        }
      }
    }

    return JsonResult.createJsonResult(0, "企业微信二次验证失败！");
  }

  /**
   * 删除对应的企业微信用户
   *
   */
  @Override
  @Secured(RoleInfo.ROLE_ADMIN)
  public JsonResult deleteWwUser(final int enterpriseId, final int id, final String remark) {
    User user = userDao.getUserById(id);
    if (user == null || user.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-1, "无此用户");
    }

    if (user.getWwUserId().length() == 0) {
      return JsonResult.createJsonResult(-2, "未找到用删除的企业微信用户ID");
    }


    BaseResponse rs = workWeixinService.deleteUser(enterpriseId, user.getWwUserId());

    if (rs.getErrcode() == 0) {
      userDao.updateWwUserId(enterpriseId, user.getId(), "");
      return JsonResult.createJsonResult(1, "删除成功");
    } else if (rs.getErrcode() == 60111) {
      //60111 	UserID不存在
      userDao.updateWwUserId(enterpriseId, user.getId(), "");
      return JsonResult.createJsonResult(1, "清理成功");
    } else if (rs.getErrcode() == 301005) {
      //301005 	不允许删除创建者
      return JsonResult.createJsonResult(-2, "不允许删除创建者");
    } else {
      logger.error("{}: {}.", rs.getErrcode(), rs.getErrmsg());
      return JsonResult.createJsonResult(-3, "删除失败：" + rs.getErrcode() + ", " + rs.getErrmsg());
    }
  }

  /**
   * 同步企业微信中某部门的成员
   *
   * @param enterpriseId 企业id
   * @param id           企业微信中对应的部门ID
   * @return 同步结果
   */
  @Override
  public JsonResult syncWwDeptUsers(final int enterpriseId, final int id) {
    try {
      ListUserResponse rs = workWeixinService.listUser(enterpriseId, id);

      for (WwUser u0 : rs.getUserlist()) {
        TmsWwUser tmsWwUser = new TmsWwUser();
        BeanUtils.copyProperties(u0, tmsWwUser);
        tmsWwUser.setId(0);
        tmsWwUser.setEnterpriseId(enterpriseId);
        tmsWwUser.setUserId(u0.getUserid());
        try {
          userDao.createTmsWwUser(tmsWwUser);
        } catch (Exception ex) {
          logger.error(ex.getMessage());
        }

        // 没有手机号的不保存到本地
        if (u0.getMobile() == null || u0.getMobile().trim().length() != 11) {
          continue;
        }

        final String mobile = u0.getMobile();
        User user = userDao.getUserByMobile(enterpriseId, mobile);
        if (user != null) {
          if (user.getWwUserId().length() == 0) {
            userDao.updateWwUserId(enterpriseId, user.getId(), u0.getUserid());

          }
          continue;
        }

        user = new User();

        // 手机号做用户名
        user.setUsername(u0.getMobile());

        // 本地关联企业微信的userId
        user.setWwUserId(u0.getUserid());

        //过滤掉表情符号
        user.setEmpname(StringUtil.filterEmoji(u0.getName(), ""));

        user.setEmail(u0.getEmail());
        user.setMobileNo(u0.getMobile());

        user.setMd5Password(VerifyCodeUtil.MD5(User.DEFAULT_PASSWORD));

        userService.createUserByRoleAdmin(user, enterpriseId, null);
      }

      return JsonResult.createJsonResult(1);
    } catch (Exception ex) {
      return JsonResult.createJsonResult(-99, ex.getMessage());
    }
  }

  /**
   * 从机票订单中导入乘机人信息
   *
   */
  @Override
  public JsonResult importPassengers(final int enterpriseId) {
    SearchFlightOrderCriteria sc = new SearchFlightOrderCriteria();
    sc.setPageSize(100);
    sc.setPageNo(1);

    int importedCount = 0; // 导入的名单人数

    //TODO 现在机票订单有英文名字输入的格式了，导入时需要区分下。
    // firstName, lastName有值就是英文名字模式
    // 只有name 有值就是中文名字模式

    while (true) {
      List<FlightOrder> orders = flightOrderDao.searchOrder(enterpriseId, "", sc, false, null);
      for (FlightOrder order : orders) {

        //订单时间超过1天则不导入了
        if (order.getCreateDate() != null && DateUtil.getPastDays(order.getCreateDate()) > 1) {
          continue;
        }

        try {
          importedCount += doImportPassenger(enterpriseId, order);
        } catch (Exception ex) {
          logger.error(ex.getMessage());
        }
      }

      if (sc.getPageNo() < sc.getPage().getPageTotal()) {
        sc.setPageNo(sc.getPageNo() + 1);
      } else {
        break;
      }
    }

    if (importedCount > 0) {
      doSendAlert(enterpriseId, "导入" + importedCount + "个乘机人资料", null, EntDepartment.DEPT_ADMINISTRATOR);
    }

    logger.info("Psg count imported: {}.", importedCount);

    return JsonResult.createJsonResult(1);
  }

  @Override
  public synchronized void importPassengerMobiles(final int enterpriseId, final String username, final int maxSeconds) {
    final long start = System.currentTimeMillis();
    List<Passenger> passengers = passengerDao.searchPsgInfoMobileIsNull(enterpriseId, 10000);

    for(Passenger psg: passengers) {
      if (psg.getIdNo() != null && psg.getIdNo().trim().length() == 18) {
        //通过身份证号导入
        List<FlightOrderPassenger> orderPassengers = flightOrderDao.searchFlightOrderPassengers(psg.getNameCn(), ID_TYPE_NI, psg.getIdNo());
        for(FlightOrderPassenger orderPsg: orderPassengers) {
          if (orderPsg.getMobile() == null || !CheckUtil.isMobileNo(orderPsg.getMobile())) {
            continue;
          }

          passengerDao.updatePassengerMobile(enterpriseId, username, psg.getId(), orderPsg.getMobile());
          break;
        }
      } else if (psg.getPassportNo() != null && psg.getPassportNo().trim().length() > 3 ) {
        //通过护照号导入
        List<FlightOrderPassenger> orderPassengers = flightOrderDao.searchFlightOrderPassengers(psg.getNameCn(), ID_TYPE_PASSPORT, psg.getPassportNo());
        for(FlightOrderPassenger orderPsg: orderPassengers) {
          if (orderPsg.getMobile() == null || !CheckUtil.isMobileNo(orderPsg.getMobile())) {
            continue;
          }

          passengerDao.updatePassengerMobile(enterpriseId, username, psg.getId(), orderPsg.getMobile());
          break;
        }
      }



      //已耗时(s)
      final long elapsedTime = (System.currentTimeMillis() - start) / 1000;

      if (elapsedTime >= maxSeconds) {
        break;
      }
    }
  }


  @Override
  public List<FuelSurcharge> searchFuelSurcharges(int enterpriseId, CommonSearchCriteria sc) {
    return enterpriseDao.searchFuelSurcharges(enterpriseId, sc);
  }

  /**
   * 保存然后附件费设置
   */
  @Override
  public JsonResult createFuelSurcharge(int enterpriseId, int mileageType, Date effectDate, int surcharge) {
    int retCode = enterpriseDao.createFuelSurcharge(enterpriseId, mileageType, effectDate, surcharge);
    return JsonResult.createJsonResult(retCode);
  }

  /**
   * 删除燃油附加费
   */
  @Override
  @Secured(RoleInfo.ROLE_ADMIN)
  public JsonResult deleteFuelSurcharge(int enterpriseId, int id) {
    int retCode = enterpriseDao.deleteFuelSurcharge(enterpriseId, id);
    return JsonResult.createJsonResult(retCode);
  }

  /**
   * 根据已注册的会员企业信息生成客户资料
   *
   */
  @Override
  public JsonResult createCustomerByEnterprise(final int enterpriseId, final int customerEnterpriseId) {
    Enterprise ce = enterpriseDao.getEnterpriseById(customerEnterpriseId);
    if (ce == null || ce.getParentEnterprise() != enterpriseId) {
      return JsonResult.createJsonResult(-1, "数据错误");
    }

    Customer c = new Customer();
    c.setEnterpriseId(enterpriseId);
    c.setCustomerEnterpriseId(customerEnterpriseId);
    c.setEnterpriseType(ENT_CORPORATION);
    c.setVipName(ce.getName());
    c.setFullName(ce.getFullName());

    int retCode = customerDao.create(c);
    return JsonResult.createJsonResult(retCode);
  }

  @Override
  @Secured(RoleInfo.ROLE_ADMIN)
  public JsonResult deletePassengerInfo(int userId, int id) {
    return JsonResult.createJsonResult(enterpriseDao.deletePassengerInfo(userId, id));
  }

  @Override
  public String searchCnAirports() {
    List<Airport> dtos = basicDataDao.searchAirportsByCountry("CN");

    for (Airport dto : dtos) {
      dto.setCityNamePinyin(convertHz2Py(dto.getCityName()));
      dto.setCityNamePy(convertHz2PyFirstChar(dto.getCityName()));
    }

    //按照拼音排序
    dtos = dtos.stream().sorted(Comparator.comparing(Airport::getCityNamePinyin))
        .collect(toList());

    StringBuilder sb = new StringBuilder();

    int count = -1;
    for (Airport dto : dtos) {
      if ("PVG".equalsIgnoreCase(dto.getThreeCode())) {
        continue;
      }
      if ("NAY".equalsIgnoreCase(dto.getThreeCode())) {
        continue;
      }

      count++;
      sb.append("citys[").append(count).append("] = new Array('");

      if ("PEK".equalsIgnoreCase(dto.getThreeCode())) {
        sb.append("BJS");
      } else {
        sb.append(dto.getThreeCode());
      }
      sb.append("','");

      sb.append(dto.getCityName());
      sb.append("','");

      sb.append(dto.getCityNamePinyin());
      sb.append("','");

      sb.append(dto.getCityNamePy());
      sb.append("');");
    }


    return sb.toString();
  }


  /**
   * 清除重复的乘机人资料
   */
  @Override
  public void cleanDuplicatePassenger(final int enterpriseId) {
    List<Passenger> passengers = passengerDao.getAll(enterpriseId);

    // 按照出现的先后排序
    passengers = passengers.stream().sorted(Comparator.comparing(Passenger::getId)).collect(toList());

    Set<String> psgSet = new HashSet<>();
    for (Passenger psg : passengers) {
      final String strPsg = psg.toString();

      if (!psgSet.add(strPsg)) {
        // 已存在，则要删除此重复的
        passengerDao.deletePassengerById(enterpriseId, psg.getId());
      }
    }
  }

  /**
   * 检查产品的有效期
   * @param enterpriseId 企业id
   * @param productCode  产品代码
   * @return 检查结果
   */
  @Override
  public JsonResult checkProductExpireDate(final int enterpriseId, final String productCode) {
    final var expiredDate = getEntExpireDate(enterpriseId);

    if (expiredDate == null) {
      return JsonResult.createJsonResult(-1, "您还未开通此功能");
    } else {
      int days = DateUtil.getDaySpan(expiredDate, DateUtil.getCurDate());
      if (days < 0) {
        return JsonResult.createJsonResult(-2, "已过期(" + DateUtil.formatDate(expiredDate, DATE_YYYY_MM_DD) + ").");
      } else {
        return JsonResult.createJsonResult(1, "使用期限:" + DateUtil.formatDate(expiredDate, DATE_YYYY_MM_DD) + ".");
      }
    }
  }

  @Override
  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_DATA_ADMIN})
  public EnterpriseConfigDto searchEntConfig(int enterpriseId) {
    EnterpriseConfigDto dto = new EnterpriseConfigDto();
    String itemValue = doGetEntCfg(enterpriseId, ENTERPRISE_PRICE_ADJUSTMENT);
    if (itemValue != null && itemValue.length() > 0) {
      try {
        dto.setPriceAdjustment(Integer.parseInt(itemValue));
      } catch (NumberFormatException ex) {
        logger.error(ex.getMessage());
      }
    }

    itemValue = enterpriseDao.getAirlineInCrazyMode(enterpriseId);
    dto.setCrazyAirlines(itemValue);

    itemValue = doGetEntCfg(enterpriseId, ENTERPRISE_DEFAULT_BOTTOM_PRICE);
    if (itemValue != null && itemValue.length() > 0) {
      try {
        dto.setBottomPrice(Integer.parseInt(itemValue));
      } catch (NumberFormatException ex) {
        logger.error(ex.getMessage());
      }
    }

    itemValue = doGetEntCfg(enterpriseId, ENTERPRISE_INCREASE_PRICE_IN_NIGHT);
    if (itemValue != null && itemValue.length() > 0) {
      try {
        dto.setIncreasePriceInNight(Integer.parseInt(itemValue));
      } catch (NumberFormatException ex) {
        logger.error(ex.getMessage());
      }
    }

    itemValue = doGetEntCfg(enterpriseId, ENTERPRISE_TBOOKING_AUTO_UPLOAD_POLICY);
    if (itemValue != null && itemValue.length() > 0) {
      try {
        if ("true".equalsIgnoreCase(itemValue)) {
          dto.setAutoUploadCtripPolicy(1);
        } else {
          dto.setAutoUploadCtripPolicy(Integer.parseInt(itemValue));
        }
      } catch (NumberFormatException ex) {
        logger.error(ex.getMessage());
      }
    }

    itemValue = doGetEntCfg(enterpriseId, ENTERPRISE_WORK_DAYS, "12345");
    dto.setWorkDay(itemValue);

    itemValue = doGetEntCfg(enterpriseId, ENTERPRISE_WORK_BEGIN_TIME, "0900");
    dto.setWorkBeginTime(itemValue);

    itemValue = doGetEntCfg(enterpriseId, ENTERPRISE_WORK_END_TIME, "1800");
    dto.setWorkEndTime(itemValue);

    dto.setReceivingAccount(doGetEntCfg(enterpriseId, ENTERPRISE_RECEIVING_ACCOUNT));

    itemValue = doGetEntCfg(enterpriseId, ENTERPRISE_TBOOKING_OFFICE);
    dto.setOfficeNo(itemValue);

    dto.setMonitorDomPolicyCount(enterpriseDao.getMonitoredDomPolicyCount(enterpriseId));
    dto.setMonitorIntlPolicyCount(enterpriseDao.getMonitoredIntlPolicyCount(enterpriseId));

    itemValue = doGetEntCfg(enterpriseId, TMS_ONE_STEP_CREATE_ORDER);
    dto.setOneStepCreateOrder("1".equalsIgnoreCase(itemValue));

    dto.setTbookingMaxLoss(doGetEntCfg(enterpriseId, ENTERPRISE_TBOOKING_MAX_LOSS, -1.0f));
    dto.setBspPrinterNo(doGetEntCfg(enterpriseId, ENTERPRISE_BSP_PRINTER, 1));

    return dto;
  }

  @Override
  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_DATA_ADMIN})
  public JsonResult updateWorkTime(int enterpriseId, String workDay, String workBeginTime, String workEndTime, String recevingAccount) {
    int saved = 0;

    int retCode = enterpriseDao.setEnterpriseConfig(enterpriseId, ENTERPRISE_WORK_DAYS, workDay);
    if (retCode == 1) {
      saved++;
    }

    retCode = enterpriseDao.setEnterpriseConfig(enterpriseId, ENTERPRISE_WORK_BEGIN_TIME, workBeginTime);
    if (retCode == 1) {
      saved++;
    }

    retCode = enterpriseDao.setEnterpriseConfig(enterpriseId, ENTERPRISE_WORK_END_TIME, workEndTime);
    if (retCode == 1) {
      saved++;
    }

    if (recevingAccount != null && recevingAccount.trim().length() > 0) {
      String account0 = doGetEntCfg(enterpriseId, ENTERPRISE_RECEIVING_ACCOUNT);
      if (account0.trim().length() == 0) {
        // 为空时才能修改
        enterpriseDao.setEnterpriseConfig(enterpriseId, ENTERPRISE_RECEIVING_ACCOUNT, recevingAccount);
      }
    }

    return JsonResult.createJsonResult(saved);
  }

  @Override
  public void updateEntConfig(final int enterpriseId, final String configKey, final String configValue) {
    enterpriseDao.setEnterpriseConfig(enterpriseId, configKey, configValue);
  }

  @Override
  public List<PnrTourCode> searchTourCodes(int enterpriseId) {
    return enterpriseDao.searchTourCodes(enterpriseId);
  }

  @Override
  @Secured({RoleInfo.ROLE_ADMIN})
  public JsonResult createOrUpdateTourCode(int enterpriseId, String username, PnrTourCode pnrTourCode) {
    int retCode;
    pnrTourCode.setEnterpriseId(enterpriseId);
    if (pnrTourCode.getId() > 0) {
      retCode = enterpriseDao.updatePnrTourCode(pnrTourCode);
    } else {
      retCode = enterpriseDao.createPnrTourCode(pnrTourCode);
    }

    return JsonResult.createJsonResult(retCode);
  }

  /**
   * 查找eterm参数, 不显示密码
   *
   */
  @Override
  public EtermEntConfig searchEtermConfig(int enterpriseId) {
    EtermEntConfig config = enterpriseDao.searchEtermConfig(enterpriseId);
    if (config != null) {
      config.setPassword("");
    }

    return config;
  }

  @Override
  @Secured({RoleInfo.ROLE_ADMIN})
  public JsonResult saveEtermConfig(int enterpriseId, String host, int port, String username, String password) {
    int retCode;

    try {
      retCode = enterpriseDao.saveEtermConfig(enterpriseId, host, port, username, password);
    } catch (RuntimeException ex) {
      retCode = -100;
      logger.error(ex.getMessage());
    }

    return JsonResult.createJsonResult(retCode);
  }

  /**
   * 设置默认供应商
   */
  @Override
  @Secured(RoleInfo.ROLE_ADMIN)
  public JsonResult setDefaultSupplier(int enterpriseId, int supplierId) {
    int retCode = enterpriseDao.setDefaultSupplier(enterpriseId, supplierId);
    return JsonResult.createJsonResult(retCode);
  }

  /**
   * 同步企业微信里面的部门信息到本地
   *
   */
  @Override
  public JsonResult syncEntDepartments(final int enterpriseId) {
    // 同步一下企业微信的部门接口
    ListDepartmentResponse rs = workWeixinService.listDepartment(enterpriseId);
    if (rs.getErrcode() == 0 && !rs.getDepartment().isEmpty()) {
      int total = 0;
      for (WwDepartment w : rs.getDepartment()) {
        EntDepartment d = new EntDepartment();
        d.setEnterpriseId(enterpriseId);

        d.setName(w.getName());
        d.setDeptId(w.getId());
        d.setParentId(w.getParentid());
        d.setOrderNo(w.getOrder());

        //检查是否有同样deptId的部门
        List<EntDepartment> departments = enterpriseDao.searchEntDepartmentByWwDeptId(enterpriseId, w.getId());

        try {
          if (departments.size() == 1) {
            d.setId(departments.get(0).getId());
          } else if (departments.size() > 1) {
            continue;
          }
          total += enterpriseDao.saveEntDepartment(d);
        } catch (RuntimeException ex) {
          logger.error(ex.getMessage());
        }
      }
      return JsonResult.createJsonResult(total, "同步了" + total + "个部门信息");
    } else {
      return JsonResult.createJsonResult(-1, rs.getErrmsg());
    }
  }

  @Override
  public JsonResult syncWwUser(int enterpriseId, int id) {
    User user = userDao.getUserById(id);
    if (user == null || user.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-1, "无此用户");
    }

    if (user.getWwUserId().length() == 0) {
      return JsonResult.createJsonResult(-2, "未找到用删除的企业微信用户ID");
    }

    try {
      WwUser rs = workWeixinService.getUser(enterpriseId, user.getWwUserId());

      if (rs.getErrcode() == 0) {

        user.setEmpname(rs.getName());
        user.setPosition(rs.getPosition());
        user.setMobileNo(rs.getMobile());
        user.setGender(Integer.parseInt(rs.getGender()));
        user.setEmail(rs.getEmail());
        user.setAvatar(rs.getAvatar());

        user.setAlias(rs.getAlias());
        user.setExternalPosition(rs.getExternalPosition());
        user.setAddress(rs.getAddress());
        user.setTelephone(rs.getTelephone());

        userDao.updateUser(enterpriseId, id, user, rs.getDepartment());

        return JsonResult.createJsonResult(1, "同步完成");
      } else {
        return JsonResult.createJsonResult(-1, rs.getErrcode() + " - " + rs.getErrmsg());
      }
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-101, ex.getMessage());
    }
  }

  private int doImportPassengerWithNationID(final int enterpriseId, final int customerId, final String psgName, final String idNo) {
    // 身份证
    List<Passenger> psgList = passengerDao.searchByNameCn(enterpriseId, customerId, psgName);

    if (!psgList.isEmpty()) {
      return 0;
    }

    Passenger newPsg = new Passenger();
    newPsg.setEnterpriseId(enterpriseId);

    if (customerId > 0) {
      Customer c = new Customer();
      c.setId(customerId);
      newPsg.setCustomer(c);
    }

    newPsg.setNameCn(psgName);
    newPsg.setNameEn(convertHz2Py(psgName));
    newPsg.setNationality("CN");

    newPsg.setIdNo(idNo);
    try {
      newPsg.setBirthday(DateUtil.convertToDate(idNo.substring(6, 14), "yyyyMMdd"));

      int evenNumber = Integer.parseInt(idNo.substring(16, 17)) % 2;
      if (evenNumber == 0) {
        newPsg.setGender(GENDER_FEMALE); // 女
      } else if (evenNumber == 1) {
        newPsg.setGender(GENDER_MALE); // 男
      }
    } catch (ParseException e) {
      logger.error(e.getMessage());
    }

    PassengerIdInfo idInfo = new PassengerIdInfo();
    idInfo.setEnterpriseId(enterpriseId);
    idInfo.setPassenger(newPsg);
    idInfo.setIdType(ID_TYPE_NI);
    idInfo.setIdNo(idNo);

    newPsg.getIdInfos().add(idInfo);

    if (passengerDao.create(newPsg) > 0) {
      return 1;
    }

    return 0;
  }

  private int doImportPassengerWithPassport(final int enterpriseId, final int customerId, final String pnrDetail) {
    int importedCount = 0;
    Pnr pnr = new Pnr();
    pnr.setPnrDetail(pnrDetail);
    for (PnrPassenger psg : pnr.getPassengers()) {
      if (psg.getIdType() != 2) {
        continue;
      }

      // 查找中文名
      List<Passenger> psgList = passengerDao.searchByNameCn(enterpriseId, customerId, psg.getPsgName());
      if (!psgList.isEmpty()) {
        continue;
      }

      // 查找英文名
      psgList = passengerDao.searchByNameEn(enterpriseId, customerId, psg.getPsgName());
      if (!psgList.isEmpty()) {
        continue;
      }

      Passenger newPsg = new Passenger();
      newPsg.setEnterpriseId(enterpriseId);

      if (customerId > 0) {
        Customer c = new Customer();
        c.setId(customerId);
        newPsg.setCustomer(c);
      }

      // 去除英文名字中的MR
      String psgName = OrderUtil.cleanMrInName(psg.getPsgName());

      newPsg.setNameEn(psgName);
      newPsg.setPassportNo(psg.getIdNo());
      newPsg.setNationality(psg.getNationality());
      newPsg.setGender(psg.getGender());
      newPsg.setBirthday(psg.getBirthday());
      newPsg.setPassportExpiry(psg.getIdExpiredDate());

      PassengerIdInfo idInfo = new PassengerIdInfo();
      idInfo.setEnterpriseId(enterpriseId);
      idInfo.setPassenger(newPsg);
      idInfo.setIdType(ID_TYPE_PASSPORT);
      idInfo.setIdNo(psg.getIdNo());
      idInfo.setIdIssueNation(psg.getNationality());
      idInfo.setIdValidDate(psg.getIdExpiredDate());

      newPsg.getIdInfos().add(idInfo);

      if (passengerDao.create(newPsg) > 0) {
        importedCount++;
      }
    }
    return importedCount;
  }

  private int doImportPassenger(final int enterpriseId, FlightOrder order) {
    if (order.getStatus() != TmsOrderConstant.FLIGHT_ORDER_STATUS_FINISHED) {
      return 0;
    }

    int idCount = 0; // 记录订单中使用身份证的人数
    final int customerId = order.getCustomer() == null ? 0 : order.getCustomer().getId();

    List<FlightOrderPassenger> passengers = order.getPassengers();

    int importedCount = 0;

    for (FlightOrderPassenger psg : passengers) {
      if (psg.getIdType() == 0) {
        continue;
      }
      String idNo = psg.getIdNo();
      if (idNo == null) {
        continue;
      }

      String psgName = psg.getName();
      if (psg.getIdType() == ID_TYPE_NI && idNo.trim().length() == 18 ) {
        idCount++;

        importedCount += doImportPassengerWithNationID(enterpriseId, customerId, psgName, idNo);
      }
    }

    if (idCount < passengers.size()) {
      // 没有使用身份证号的，可能用的是护照
      importedCount += doImportPassengerWithPassport(enterpriseId, customerId, order.getPnrDetail());

    }

    return importedCount;
  }


  private String convertHz2Py(String hz) {
    HanyuPinyinOutputFormat pyformat = new HanyuPinyinOutputFormat();
    pyformat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);

    StringBuilder py = new StringBuilder();
    try {
      for (int i = 0; i < hz.length(); i++) {
        String[] pinyins = PinyinHelper.toHanyuPinyinStringArray(hz.charAt(i), pyformat);
        if (pinyins.length > 0) {
          py.append(pinyins[0]);
        }
      }
    } catch (BadHanyuPinyinOutputFormatCombination ex) {
      logger.error(ex.getMessage());
    }

    return py.toString().toUpperCase();
  }

  private String convertHz2PyFirstChar(String hz) {
    HanyuPinyinOutputFormat pyformat = new HanyuPinyinOutputFormat();
    pyformat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);

    StringBuilder py = new StringBuilder();
    try {
      for (int i = 0; i < hz.length(); i++) {
        String[] pinyins = PinyinHelper.toHanyuPinyinStringArray(hz.charAt(i), pyformat);
        if (pinyins.length > 0) {
          py.append(pinyins[0].charAt(0));
        }
      }
    } catch (BadHanyuPinyinOutputFormatCombination ex) {
      logger.error(ex.getMessage());
    }

    return py.toString().toUpperCase();
  }


  @Override
  public Date getEntExpireDate(int enterpriseId) {
    return enterpriseDao.getEntExpireDate(enterpriseId);
  }



  @Override
  public SmsConfigDto searchSmsConfig(final int enterpriseId) {
    final String companySign = doGetEntCfg(enterpriseId, API_SMS_COMPANY_SIGN);
    final String apiUrl = doGetEntCfg(enterpriseId, API_SMS_URL);
    final String accessKey = doGetEntCfg(enterpriseId, API_SMS_ACCESS_KEY);

    SmsConfigDto dto = new SmsConfigDto();

    dto.setAccessKey(accessKey);
    dto.setUrl(apiUrl);
    dto.setCompanySign(companySign);

    return dto;
  }

  @Override
  @Secured({RoleInfo.ROLE_ADMIN})
  public JsonResult updateSmsConfig(int enterpriseId, String username, String companySign, String url,
      String accessKey, String secretKey) {

    if ("demo".equalsIgnoreCase(username)) {
      return JsonResult.createJsonResult(-1, "该用户不允许修改");
    }

    try {
      enterpriseDao
          .setEnterpriseConfig(enterpriseId, API_SMS_COMPANY_SIGN, companySign);

      enterpriseDao.setEnterpriseConfig(enterpriseId, API_SMS_URL, url);

      if (secretKey != null && secretKey.trim().length() > 0) {
        enterpriseDao
            .setEnterpriseConfig(enterpriseId, API_SMS_SECRET_KEY, secretKey);
      }
      enterpriseDao
          .setEnterpriseConfig(enterpriseId, API_SMS_ACCESS_KEY, accessKey);

      return JsonResult.createJsonResult(1);

    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Override
  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_DATA_ADMIN})
  @Transactional
  public JsonResult updateOrderConfig(final int enterpriseId, final String username, OrderConfigDto configDto) {
    execUpdateEntCfg(enterpriseId, TMS_ONE_STEP_CREATE_ORDER, configDto.getOneStepCreateOrder());
    execUpdateEntCfg(enterpriseId, TMS_HIDE_CUSTOMER_NAME, configDto.getHideCustomerName());
    execUpdateEntCfg(enterpriseId, TMS_OP1_SEE_OWN_ORDER, configDto.getIsOnlySeeOwn());
    if (execUpdateEntCfg(enterpriseId, TMS_AUTO_TICKET_MODE, configDto.getAutoTicketMode()) > 0) {
      doSendAlert(enterpriseId, "自动出票类型更改为" + configDto.getAutoTicketMode(), null, EntDepartment.DEPT_ADMINISTRATOR);
    }
    execUpdateEntCfg(enterpriseId, TMS_AUTO_TICKETING_SWITCH, configDto.getAutoTicketSwitch());
    execUpdateEntCfg(enterpriseId, TMS_ORDER_VALIDATE_MODE, configDto.getValidationMode());

    return JsonResult.createJsonResult(1);
  }

  /**
   * 执行修改企业参数：参数对应的值有变化则修改
   * @param enterpriseId 企业id
   * @param itemCode 参数key
   * @param newVal 参数新的值
   * @return 修改结果
   *      0 - 未修改
   *      >0 - 已修改或新建
   */
  private int execUpdateEntCfg(final int enterpriseId, final String itemCode, final int newVal) {
    final int oldVal = doGetEntCfg(enterpriseId, itemCode, 0);
    if (oldVal != newVal) {
      return enterpriseDao.setEnterpriseConfig(enterpriseId, itemCode, newVal + "");
    } else {
      return 0;
    }
  }

  @Override
  public List<DataFieldInfo> searchDataFields() {
    return enterpriseDao.searchDataFields();
  }

  private DataFieldInfo getDataFieldInfoById(int id) {
    return enterpriseDao.getDataFieldInfoById(id);
  }

  @Override
  public JsonResult createDataTemplate(final int enterpriseId, DataTemplateDto dto) {

    //检查已有的数量
    List<DataFieldExportTemplate> templates = enterpriseDao.searchDataTemplates(enterpriseId);
    final int allowedCount = doGetEntCfg(enterpriseId, DATA_TEMPLATE_COUNT, 5);
    if (templates.size() > allowedCount) {
      logger.info("Template's count is too much.");
      return JsonResult.createJsonResult(-2, "模板数量已超过限制");
    }

    if (dto.getName() == null || dto.getName().trim().length() == 0) {
      return JsonResult.createJsonResult(-1, "模板名称必需填写");
    }

    DataFieldExportTemplate template = new DataFieldExportTemplate();

    template.setName(dto.getName());
    template.setEnterpriseId(enterpriseId);

    int columnIndex = 0;
    for(DataFieldInfo fieldInfo: dto.getFlightFields()) {
      columnIndex++;
      DataFieldExportInfo exportInfo = new DataFieldExportInfo();
      exportInfo.setAlias(fieldInfo.getName());
      exportInfo.setColumnIndex(columnIndex);

      exportInfo.setDataFieldInfo(getDataFieldInfoById(fieldInfo.getId()));
      exportInfo.setDataType(DataFieldInfo.DATA_TYPE_FLIGHT);

      exportInfo.setTemplate(template);

      template.getExportFields().add(exportInfo);
    }

    columnIndex = 0;
    for(DataFieldInfo fieldInfo: dto.getRefundFields()) {
      columnIndex++;
      DataFieldExportInfo exportInfo = new DataFieldExportInfo();
      exportInfo.setAlias(fieldInfo.getName());
      exportInfo.setColumnIndex(columnIndex);

      exportInfo.setDataFieldInfo(getDataFieldInfoById(fieldInfo.getId()));
      exportInfo.setDataType(DataFieldInfo.DATA_TYPE_FLIGHT_REFUND);

      exportInfo.setTemplate(template);

      template.getExportFields().add(exportInfo);
    }

    columnIndex = 0;
    for(DataFieldInfo fieldInfo: dto.getChangeFields()) {
      columnIndex++;
      DataFieldExportInfo exportInfo = new DataFieldExportInfo();
      exportInfo.setAlias(fieldInfo.getName());
      exportInfo.setColumnIndex(columnIndex);

      exportInfo.setDataFieldInfo(getDataFieldInfoById(fieldInfo.getId()));
      exportInfo.setDataType(DataFieldInfo.DATA_TYPE_FLIGHT_CHANGE);

      exportInfo.setTemplate(template);

      template.getExportFields().add(exportInfo);
    }

    columnIndex = 0;
    for(DataFieldInfo fieldInfo: dto.getHotelFields()) {
      columnIndex++;
      DataFieldExportInfo exportInfo = new DataFieldExportInfo();
      exportInfo.setAlias(fieldInfo.getName());
      exportInfo.setColumnIndex(columnIndex);

      exportInfo.setDataFieldInfo(getDataFieldInfoById(fieldInfo.getId()));

        exportInfo.setDataType(DataFieldInfo.DATA_TYPE_HOTEL);

      exportInfo.setTemplate(template);

      template.getExportFields().add(exportInfo);
    }

    columnIndex = 0;
    for(DataFieldInfo fieldInfo: dto.getTrainFields()) {
      columnIndex++;
      DataFieldExportInfo exportInfo = new DataFieldExportInfo();
      exportInfo.setAlias(fieldInfo.getName());
      exportInfo.setColumnIndex(columnIndex);

      exportInfo.setDataFieldInfo(getDataFieldInfoById(fieldInfo.getId()));

      exportInfo.setDataType(DataFieldInfo.DATA_TYPE_TRAIN);

      exportInfo.setTemplate(template);

      template.getExportFields().add(exportInfo);
    }

    columnIndex = 0;
    for(DataFieldInfo fieldInfo: dto.getVasFields()) {
      columnIndex++;
      DataFieldExportInfo exportInfo = new DataFieldExportInfo();
      exportInfo.setAlias(fieldInfo.getName());
      exportInfo.setColumnIndex(columnIndex);

      exportInfo.setDataFieldInfo(getDataFieldInfoById(fieldInfo.getId()));

      exportInfo.setDataType(DataFieldInfo.DATA_TYPE_VAS);

      exportInfo.setTemplate(template);

      template.getExportFields().add(exportInfo);
    }

    for(DataFieldExportInfo exportInfo: template.getExportFields()) {
      exportInfo.setEnterpriseId(enterpriseId);
    }

    template.setTemplateNo(orderNoGenerator.generateTemplateNo(enterpriseId,
        OrderNoInfo.DATA_TEMPLATE));

    return JsonResult.createJsonResult(enterpriseDao.createDataTemplate(template));
  }

  @Override
  public List<DataFieldExportTemplate> searchDataTemplates(int enterpriseId,
      CommonSearchCriteria sc) {
    return enterpriseDao.searchDataTemplates(enterpriseId, sc);
  }

  @Override
  public DataFieldExportTemplate searchDataTemplate(int enterpriseId, int templateNo) {
    return enterpriseDao.searchDataTemplate(enterpriseId, templateNo);
  }

  @Override
  public JsonResult deleteDataTemplateById(int enterpriseId, int id) {
    int retCode = enterpriseDao.deleteDataTemplateById(enterpriseId, id);
    return JsonResult.createJsonResult(retCode);
  }

  @Override
  public VaasConfigDto searchVaasConfig(final int enterpriseId) {
    final String apiUrl = doGetEntCfg(enterpriseId, API_VAAS_URL);
    final String secretKey = doGetEntCfg(enterpriseId, API_VAAS_SECRET_KEY);
    final String username = doGetEntCfg(enterpriseId, API_VAAS_USERNAME);

    VaasConfigDto dto = new VaasConfigDto();

    dto.setUrl(apiUrl);
    dto.setUsername(username);
    dto.setSecretKey(secretKey);

    return dto;
  }

  @Override
  public OrderConfigDto searchOrderConfig(final int enterpriseId) {

    OrderConfigDto dto = new OrderConfigDto();

    dto.setOneStepCreateOrder(enterpriseDao.getEnterpriseConfig(enterpriseId, TMS_ONE_STEP_CREATE_ORDER, 0));
    dto.setHideCustomerName(enterpriseDao.getEnterpriseConfig(enterpriseId, TMS_HIDE_CUSTOMER_NAME, 0));
    dto.setIsOnlySeeOwn(enterpriseDao.getEnterpriseConfig(enterpriseId, TMS_OP1_SEE_OWN_ORDER, 0));
    dto.setAutoTicketMode(enterpriseDao.getEnterpriseConfig(enterpriseId, TMS_AUTO_TICKET_MODE, 0));
    dto.setAutoTicketSwitch(enterpriseDao.getEnterpriseConfig(enterpriseId, TMS_AUTO_TICKETING_SWITCH, 0));
    dto.setValidationMode(enterpriseDao.getEnterpriseConfig(enterpriseId, TMS_ORDER_VALIDATE_MODE, 0));

    return dto;
  }

  @Override
  public JsonResult updateVaasConfig(int enterpriseId, String username, String url,
      String apiUsername, String secretKey) {
    if ("demo".equalsIgnoreCase(username)) {
      return JsonResult.createJsonResult(-1, "该用户不允许修改");
    }

    try {
      enterpriseDao
          .setEnterpriseConfig(enterpriseId, API_VAAS_URL, url);

      enterpriseDao.setEnterpriseConfig(enterpriseId, API_VAAS_USERNAME, apiUsername);

      if (secretKey != null && secretKey.trim().length() > 0) {
        enterpriseDao
            .setEnterpriseConfig(enterpriseId, API_VAAS_SECRET_KEY, secretKey);
      }

      return JsonResult.createJsonResult(1);

    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Override
  public String[] searchPossibleCustomers(final int enterpriseId, PassengerDto[] dtos) {
    Map<Integer, String> customerSet = new HashMap<>();

    for(PassengerDto dto: dtos) {
      List<Passenger> passengers = passengerDao.searchByName(enterpriseId, 0, dto.getName());
      for(Passenger passenger: passengers) {
        if (passenger.getCustomer() != null) {
          final int customerId = passenger.getCustomer().getId();
          final String customerName = passenger.getCustomer().getVipName();

          if (dto.getIdNo() == null || dto.getIdNo().trim().length() == 0) {
            //无证件号
            customerSet.put(customerId, customerName);
          } else {
            //有证件号
            final String idNo = dto.getIdNo().trim();
            if (idNo.equalsIgnoreCase(passenger.getIdNo()) || idNo.equalsIgnoreCase(passenger.getPassportNo())) {
              customerSet.put(customerId, customerName);
            } else {
              for(PassengerIdInfo idInfo: passenger.getIdInfos()) {
                if (idNo.equalsIgnoreCase(idInfo.getIdNo())) {
                  customerSet.put(customerId, customerName);
                  break;
                }
              }
            }
          }
        }
      }
    }

    return customerSet.values().toArray(new String[0]);
  }

  @Override
  public void refreshCustomerRecency() {
    enterpriseDao.refreshCustomerRecency();
  }


  @Override
  public void refreshSupplierFrequency() {
    try {
      enterpriseDao.refreshSupplierFrequency();
    } catch (Exception ex) {
      logger.error(ex.getMessage());
      ex.printStackTrace();
    }
  }

  @Override
  public void saveBasicData2Redis() {
    //DONE 以下数据，最多5分钟更新一次
    doSaveAirportInfo2Redis();
    doSaveAirlinesInfo2Redis();

    //DONE 以下数据，最多5分钟更新一次
    if (this.getOwnerId() > 0) {
      doSaveLuggageInfo2Redis(this.getOwnerId());
      doSaveSubclassInfo2Redis(this.getOwnerId());
    }
  }

  @Override
  public void saveBusinessData2Redis() {
    if (this.getOwnerId() < 1) {
      return;
    }
    //把ownerId的全局加价放入到redis
    doSaveGlobalMarkup2Redis();

    //把客户享受的其它优惠放入到redis
    List<Integer> customerEnterpriseIds = enterpriseDao.searchCustomerEnterpriseId(this.getOwnerId(), 0);
    for (int ceid : customerEnterpriseIds) {
      doSaveCustomerOtDiscount2Redis(ceid);
    }

    //把客户享受的机票优惠放入到redis
    customerEnterpriseIds = enterpriseDao.searchCustomerEnterpriseId(this.getOwnerId(), 1);
    for (int ceid : customerEnterpriseIds) {
      doSaveCustomerFlightDiscount2Redis(ceid);
    }

    //把为企业客户设置的航班查询参数放到redis
    customerEnterpriseIds = enterpriseDao.searchCustomerEnterpriseId(this.getOwnerId(), 0);
    for (int ceid : customerEnterpriseIds) {
      doSaveCustomerAvCountInfo2Redis(ceid);
    }
  }

  /**
   * 保存航司行李信息到redis
   */
  private void doSaveLuggageInfo2Redis(final int ownerId) {
    List<Airline> airlines = basicDataDao.getAllAirlines();
    for(Airline airline: airlines) {
      List<LuggageInfo> luggageInfos = basicDataDao.searchLuggageInfos(ownerId, airline.getTwoCode());
      if (luggageInfos.isEmpty()) {
        continue;
      }

      final String key = String.format(TmsConstant.AIRLINES_LUGGAGE_INFO, ownerId, airline.getTwoCode());
      final String newJsonStr = JSON.toJSONString(luggageInfos);
      execSetRedisContent(key, newJsonStr, 60 * 60 * 24 * 7);
    }
  }

  /**
   * 保存航司舱位信息到redis
   */
  private void doSaveSubclassInfo2Redis(final int ownerId) {
    List<Airline> airlines = basicDataDao.getAllAirlines();
    for(Airline airline: airlines) {
      List<SubclassInfo> subclassInfos = basicDataDao.searchSubclassInfos(ownerId, airline.getTwoCode());
      if (subclassInfos.isEmpty()) {
        continue;
      }

      List<FlightCondTimeWindowDto> timeWindows = basicDataService.searchFlightConditionTimeWindows(airline.getTwoCode());


      AirlinesTgqInfo tgqInfo = new AirlinesTgqInfo();
      tgqInfo.setSubclassInfos(subclassInfos);
      tgqInfo.setTimeWindows(timeWindows);

      final String key = String.format(TmsConstant.AIRLINES_TGQ_INFO, ownerId, airline.getTwoCode());
      final String newJsonStr = JSON.toJSONString(tgqInfo);
      execSetRedisContent(key, newJsonStr, 60 * 60 * 24 * 7);
    }
  }

  /**
   * 将机场信息保存到redis
   */
  private void doSaveAirportInfo2Redis() {
    List<Airport> airports = basicDataDao.getAllAirports();
    for(Airport airport: airports) {
      final String key = String.format(TmsConstant.AIRPORT_INFO, airport.getThreeCode());
      final String newJsonStr = JSON.toJSONString(airport);
      execSetRedisContent(key, newJsonStr, 60 * 60 * 24 * 30);
    }
  }

  /**
   * 将航司信息保存到redis
   */
  private void doSaveAirlinesInfo2Redis() {
    List<Airline> airlines = basicDataDao.getAllAirlines();
    for(Airline airline: airlines) {
      final String key = String.format(TmsConstant.AIRLINES_INFO, airline.getTwoCode());
      final String newJsonStr = JSON.toJSONString(airline);
      execSetRedisContent(key, newJsonStr, 60 * 60 * 24 * 30);
    }
  }

  /**
   * 将全局加价信息保存到redis
   */
  private void doSaveGlobalMarkup2Redis() {
    MarkupConfigDto markupConfigDto = this.searchMarkupConfig(this.getOwnerId());

    final String key = String.format(TmsConstant.GLOBAL_MARKUP, this.getOwnerId());
    final String newJsonStr = JSON.toJSONString(markupConfigDto);

    execSetRedisContent(key, newJsonStr, 60 * 6, 1);
  }

  /**
   * 将客户享受的其它优惠信息保存到redis
   */
  private void doSaveCustomerOtDiscount2Redis(final int ceid) {
    CustomerDiscountInfoDto discountInfoDto = this.doGetCustomerDiscountInfo(ceid);

    final String key = String.format(TmsConstant.CUSTOMER_OT_DISCOUNT, this.getOwnerId(), ceid);
    final String newJsonStr = JSON.toJSONString(discountInfoDto);

    execSetRedisContent(key, newJsonStr, 60 * 6, 1);
  }

  /**
   * 将客户享受的机票优惠信息保存到redis
   * @param ceid 客户的企业id customer enterprise id
   */
  private void doSaveCustomerFlightDiscount2Redis(final int ceid) {
    List<CustomerFlightDiscountDto> discountDtos = this.doGetCustomerFlightDiscount(this.getOwnerId(), ceid);
    final String key = String.format(TmsConstant.CUSTOMER_FLIGHT_DISCOUNT, this.getOwnerId(), ceid);
    final String newJsonStr = JSON.toJSONString(discountDtos);

    execSetRedisContent(key, newJsonStr, 60 * 6, 1);
  }

  /**
   * 将企业客户的航班查询次数控制信息保存到redis
   */
  private void doSaveCustomerAvCountInfo2Redis(final int ceid) {
    CustomerAvCountInfoDto dto = this.doGetCustomerAvCountInfo(ceid);
    final String key = String.format(CUSTOMER_AV_COUNT, this.getOwnerId(), ceid);
    final String newJsonStr = JSON.toJSONString(dto);

    execSetRedisContent(key, newJsonStr, 60 * 6, 1);
  }

  @Override
  public MarkupConfigDto searchMarkupConfig(int enterpriseId) {
    final int hotelMarkup = doGetEntCfg(enterpriseId, GLOBAL_HOTEL_MARKUP, 0);
    final int carMarkup = doGetEntCfg(enterpriseId, GLOBAL_CAR_MARKUP, 0);
    final int boardingCardMarkup = doGetEntCfg(enterpriseId, GLOBAL_BOARDING_CARD_MARKUP, 15);
    final int domFlightMarkup = doGetEntCfg(enterpriseId, GLOBAL_DOM_FLIGHT_MARKUP, 0);
    final int intlFlightMarkup = doGetEntCfg(enterpriseId, GLOBAL_INTL_FLIGHT_MARKUP, 0);

    MarkupConfigDto dto = new MarkupConfigDto();

    dto.setHotelMarkup(hotelMarkup);
    dto.setCarMarkup(carMarkup);
    dto.setBoardingCardMarkup(boardingCardMarkup);
    dto.setDomFlightMarkup(domFlightMarkup);
    dto.setIntlFlightMarkup(intlFlightMarkup);

    return dto;
  }

  @Override
  @Transactional
  public JsonResult saveMarkupConfig(int enterpriseId, int hotelMarkup, int carMarkup, int boardingCardMarkup, int domFlightMarkup, int intlFlightMarkup) {

    enterpriseDao.setEnterpriseConfig(enterpriseId, GLOBAL_HOTEL_MARKUP, hotelMarkup + "");
    enterpriseDao.setEnterpriseConfig(enterpriseId, GLOBAL_CAR_MARKUP, carMarkup + "");
    enterpriseDao.setEnterpriseConfig(enterpriseId, GLOBAL_BOARDING_CARD_MARKUP, boardingCardMarkup + "");
    enterpriseDao.setEnterpriseConfig(enterpriseId, GLOBAL_DOM_FLIGHT_MARKUP, domFlightMarkup + "");
    enterpriseDao.setEnterpriseConfig(enterpriseId, GLOBAL_INTL_FLIGHT_MARKUP, intlFlightMarkup + "");

    return JsonResult.createJsonResult(1);
  }

  @Override
  public CustomerDiscountInfoDto getCustomerDiscountInfo(int enterpriseId, int id) {
    CustomerDiscountInfoDto dto = new CustomerDiscountInfoDto();

    Customer c = customerDao.getCustomerById(id);
    if (c == null || c.getEnterpriseId() != enterpriseId) {
      dto.setErrcode(40000);
      dto.setErrmsg("无此客户信息");
      return dto;
    }

    //获取优惠信息
    if (c.getCustomerEnterpriseId() > 0) {
      dto = doGetCustomerDiscountInfo(c.getCustomerEnterpriseId());
    } else {
      dto.setErrcode(40001);
      dto.setErrmsg("无此客户企业信息");
    }

    return dto;
  }

  @Override
  public CustomerAvCountInfoDto getCustomerAvCountInfo(int enterpriseId, int id) {
    CustomerAvCountInfoDto dto = new CustomerAvCountInfoDto();

    Customer c = customerDao.getCustomerById(id);
    if (c == null || c.getEnterpriseId() != enterpriseId) {
      dto.setErrcode(40000);
      dto.setErrmsg("无此客户信息");
      return dto;
    }

    //获取优惠信息
    if (c.getCustomerEnterpriseId() > 0) {
      dto = doGetCustomerAvCountInfo(c.getCustomerEnterpriseId());
    } else {
      dto.setErrcode(40001);
      dto.setErrmsg("无此客户企业信息");
    }

    return dto;
  }

  private CustomerDiscountInfoDto doGetCustomerDiscountInfo(final int customerEnterpriseId) {
    final int hotelDiscount = enterpriseDao.getEnterpriseConfig(customerEnterpriseId, CUSTOMER_HOTEL_DISCOUNT, 0);
    final int carDiscount = enterpriseDao.getEnterpriseConfig(customerEnterpriseId, CUSTOMER_CAR_DISCOUNT, 0);
    final int cardDiscount = enterpriseDao.getEnterpriseConfig(customerEnterpriseId, CUSTOMER_BOARDING_CARD_DISCOUNT, 0);
    final int domFlightDiscount = enterpriseDao.getEnterpriseConfig(customerEnterpriseId, CUSTOMER_DOM_FLIGHT_DISCOUNT, 0);
    final int intlFlightDiscount = enterpriseDao.getEnterpriseConfig(customerEnterpriseId, CUSTOMER_INTL_FLIGHT_DISCOUNT, 0);

    CustomerDiscountInfoDto dto = new CustomerDiscountInfoDto();

    dto.setHotelDiscount(hotelDiscount);
    dto.setCarDiscount(carDiscount);
    dto.setBoardingCardDiscount(cardDiscount);
    dto.setDomFlightDiscount(domFlightDiscount);
    dto.setIntlFlightDiscount(intlFlightDiscount);

    return dto;
  }

  private CustomerAvCountInfoDto doGetCustomerAvCountInfo(final int customerEnterpriseId) {
    final int avMaxTotal = enterpriseDao.getEnterpriseConfig(customerEnterpriseId, CUSTOMER_AV_MAX_TOTAL, 0);
    final int avMaxMonthly = enterpriseDao.getEnterpriseConfig(customerEnterpriseId, CUSTOMER_AV_MAX_MONTHLY, 100);
    final int usedTotal = enterpriseDao.getEnterpriseConfig(customerEnterpriseId, CUSTOMER_AV_USED_TOTAL, 0);
    final int usedMonthly = enterpriseDao.getEnterpriseConfig(customerEnterpriseId, CUSTOMER_AV_USED_MONTHLY, 0);

    CustomerAvCountInfoDto dto = new CustomerAvCountInfoDto();

    dto.setTotalMax(avMaxTotal);
    dto.setTotalUsed(usedTotal);
    dto.setMonthlyMax(avMaxMonthly);
    dto.setMonthlyUsed(usedMonthly);

    return dto;
  }


  @Override
  public JsonResult saveCustomerDiscountInfo(int enterpriseId, int customerId, int hotelDiscount, int carDiscount, int boardingCardDiscount, int domFlightDiscount, int intlFlightDiscount) {
    final int globalDomFlightMarkup = enterpriseDao.getEnterpriseConfig(enterpriseId, GLOBAL_DOM_FLIGHT_MARKUP, 0);
    if (domFlightDiscount < 0 || domFlightDiscount > globalDomFlightMarkup) {
      return JsonResult.createJsonResult(-1, "国内机票优惠金额超过系统限制");
    }

    final int globalIntlFlightMarkup = enterpriseDao.getEnterpriseConfig(enterpriseId, GLOBAL_INTL_FLIGHT_MARKUP, 0);
    if (intlFlightDiscount < 0 || intlFlightDiscount > globalIntlFlightMarkup) {
      return JsonResult.createJsonResult(-1, "国际机票优惠金额超过系统限制");
    }


    final int globalHotelMarkup = enterpriseDao.getEnterpriseConfig(enterpriseId, GLOBAL_HOTEL_MARKUP, 0);
    if (hotelDiscount > globalHotelMarkup) {
      return JsonResult.createJsonResult(-1, "酒店优惠金额超过系统限制");
    }

    final int globalCarMarkup = enterpriseDao.getEnterpriseConfig(enterpriseId, GLOBAL_CAR_MARKUP, 0);
    if (carDiscount > globalCarMarkup) {
      return JsonResult.createJsonResult(-1, "用车优惠金额超过系统限制");
    }

    final int globalCardMarkup = enterpriseDao.getEnterpriseConfig(enterpriseId, GLOBAL_BOARDING_CARD_MARKUP, 0);
    if (boardingCardDiscount > globalCardMarkup) {
      return JsonResult.createJsonResult(-1, "登机牌办理优惠金额超过系统限制");
    }


    Customer c = customerDao.getCustomerById(customerId);
    if (c.getCustomerEnterpriseId() > 0) {
      final int ceid = c.getCustomerEnterpriseId();
      enterpriseDao.setEnterpriseConfig(ceid, CUSTOMER_HOTEL_DISCOUNT, hotelDiscount + "");
      enterpriseDao.setEnterpriseConfig(ceid, CUSTOMER_CAR_DISCOUNT, carDiscount + "");
      enterpriseDao.setEnterpriseConfig(ceid, CUSTOMER_BOARDING_CARD_DISCOUNT, boardingCardDiscount + "");
      enterpriseDao.setEnterpriseConfig(ceid, CUSTOMER_DOM_FLIGHT_DISCOUNT, domFlightDiscount + "");
      enterpriseDao.setEnterpriseConfig(ceid, CUSTOMER_INTL_FLIGHT_DISCOUNT, intlFlightDiscount + "");
      return JsonResult.createJsonResult(1);
    } else {
      return JsonResult.createJsonResult(-2, "此用户暂时无法设置优惠金额");
    }
  }

  @Override
  public List<CustomerFlightDiscountDto> searchCustomerFlightDiscounts(final int enterpriseId, final int customerId) {
    Customer c = customerDao.getCustomerById(customerId);
    if (c == null || c.getEnterpriseId() != enterpriseId) {
      return new ArrayList<>();
    }

    final int customerEnterpriseId = c.getCustomerEnterpriseId();

    return this.doGetCustomerFlightDiscount(enterpriseId, customerEnterpriseId);
  }

  /**
   * 获取为企业客户设置的机票优惠信息
   */
  private List<CustomerFlightDiscountDto> doGetCustomerFlightDiscount(final int ownerId, final int customerEnterpriseId) {
    List<CustomerFlightDiscount> list = enterpriseDao.searchCustomerFlightDiscounts(ownerId, customerEnterpriseId);

    List<CustomerFlightDiscountDto> dtos = new ArrayList<>();
    for(CustomerFlightDiscount info: list) {
      FlightKeyCustomerPolicy policy = keyCustomerPolicyDao.searchFlightKeyCustomerPolicy(ownerId, info.getPolicyCode());
      if (policy == null) {
        continue;
      }

      CustomerFlightDiscountDto dto = new CustomerFlightDiscountDto();

      BeanUtils.copyProperties(policy, dto);
      dto.setCommissionRateRetained(info.getCommissionRateRetained());

      dtos.add(dto);
    }

    return dtos;
  }

  @Override
  public JsonResult saveCustomerFlightDiscount(int enterpriseId, int customerId, String policyCode, int commRateRetained, int mode) {
    Customer c = customerDao.getCustomerById(customerId);
    if (c == null || c.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-1, "不存在此客户");
    }

    int retCode;
    if (mode == 0) {
      CustomerFlightDiscount info = new CustomerFlightDiscount();
      info.setEnterpriseId(enterpriseId);
      info.setCustomerEnterpriseId(c.getCustomerEnterpriseId());
      info.setPolicyCode(policyCode);
      info.setCommissionRateRetained(commRateRetained);

      //校验policyCode
      FlightKeyCustomerPolicy p = keyCustomerPolicyDao.searchFlightKeyCustomerPolicy(enterpriseId, policyCode);
      if (p == null || p.getStatus() == 0 || p.getExpireDate().getTime() < DateUtil.getCurDate().getTime()) {
        return JsonResult.createJsonResult(-1, "无此政策或不可用");
      }


      try {
        retCode = enterpriseDao.saveCustomerFlightDiscount(info);
      } catch (RuntimeException ex) {
        return JsonResult.createJsonResult(-100, ex.getMessage());
      }
    } else {
      //删除
      retCode = enterpriseDao.deleteCustomerFlightDiscount(enterpriseId, c.getCustomerEnterpriseId(), policyCode);
    }

    return JsonResult.createJsonResult(retCode);
  }

  @Override
  @Secured({RoleInfo.ROLE_DATA_ADMIN, RoleInfo.ROLE_ADMIN})
  public JsonResult createVehicleGroupInfo(int enterpriseId, String username, VehicleGroupInfoDto dto) {
    try {
      ValidationUtils.validate(dto);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-1, ex.getMessage());
    }

    try {
      VehicleGroupInfo info = VehicleGroupInfoDto.convertTo(dto);
      info.setEnterpriseId(enterpriseId);

      int retCode = enterpriseDao.createVehicleGroupInfo(enterpriseId, username, info);

      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Override
  public List<VehicleGroupInfoDto> searchVehicleGroups(int enterpriseId, CommonSearchCriteria sc, int mapping) {
    List<VehicleGroupInfo> infos = enterpriseDao.searchVehicleGroups(enterpriseId, sc);

    List<VehicleGroupInfoDto> dtos = new ArrayList<>();

    for(VehicleGroupInfo info: infos) {
      VehicleGroupInfoDto dto = new VehicleGroupInfoDto();
      BeanUtils.copyProperties(info, dto);

      dtos.add(dto);
    }


    if (mapping == 1) {
      //返回对应车型组的映射信息
      List<Integer> ids = new ArrayList<>();
      for(VehicleGroupInfoDto dto: dtos) {
        ids.add(dto.getId());
      }

      List<VehicleGroupMapping> mappings = enterpriseDao.searchVehicleGroupMappings(enterpriseId, ids);

      for(VehicleGroupMapping m: mappings) {
        for(VehicleGroupInfoDto dto: dtos) {
          if (m.getVehicleGroupInfo().getId() == dto.getId()) {

            VehicleGroupMappingDto mappingDto = new VehicleGroupMappingDto();
            mappingDto.setId(m.getId());
            mappingDto.setVehicleGroupId(dto.getId());
            mappingDto.setVehicleGroupName(dto.getName());
            mappingDto.setSupplierName(m.getSupplier().getName());
            mappingDto.setSupplierVehicleGroupId(m.getSupplierVehicleGroupId());

            dto.getMappings().add(mappingDto);
            break;
          }
        }
      }

    }

    return dtos;
  }

  @Override
  public JsonResult createVehicleGroupMapping(int enterpriseId, String username, int vehicleId, int supplierId, int supplierVehicleId) {
    VehicleGroupInfo info = enterpriseDao.getVehicleGroupInfoById(vehicleId);
    if (info == null || info.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-1, "车型组信息错误");
    }

    Supplier supplier = enterpriseDao.getSupplierById(supplierId);
    if (supplier == null || supplier.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-2, "供应商信息错误");
    }

    if (supplierVehicleId <= 0) {
      return JsonResult.createJsonResult(-3, "供应商车型组ID 错误");
    }

    VehicleGroupMapping mapping = new VehicleGroupMapping();
    mapping.setVehicleGroupInfo(info);
    mapping.setSupplier(supplier);
    mapping.setSupplierVehicleGroupId(supplierVehicleId);

    try {
      int retCode = enterpriseDao.createVehicleGroupMapping(enterpriseId, username, mapping);
      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Override
  public CustomerDepartmentDto getCustomerDepartmentById(int enterpriseId, int id) {
    CustomerDepartment o = enterpriseDao.getCustomerDepartmentById(id);

    if (o == null || o.getEnterpriseId() != enterpriseId) {
      return null;
    }

    return getCustomerDepartmentDto(o);
  }

  private CustomerDepartmentDto getCustomerDepartmentDto(CustomerDepartment o) {
    CustomerDepartmentDto dto = CustomerDepartmentDto.createBy(o);

    final int customerId =  o.getCustomer().getId();
    final int enterpriseId = o.getEnterpriseId();

    dto.setCustomerId(customerId);
    dto.setCustomerName(o.getCustomer().getVipName());

    if (o.getParentDepartmentNo() > 0) {
      CustomerDepartment department = enterpriseDao.getCustomerDepartmentByDeptId(enterpriseId, customerId, o.getParentDepartmentNo());
      if (department != null) {
        dto.setParentDepartmentName(department.getName());
      }
    }

    //获取审批人信息
    List<CustomerTravelApprover> approvers = customerDao.searchCustomerApprovers(enterpriseId, customerId, dto.getId());
    for(CustomerTravelApprover ta: approvers) {
      CustomerTravelApproverDto taDto = CustomerTravelApproverDto.createdBy(ta);

      if (ta.getUser().getPassengerId() != null) {
        Passenger passenger = passengerDao.getById(ta.getUser().getPassengerId());
        if (passenger != null && passenger.getPosition() != null) {
          taDto.setPositionId(passenger.getPosition().getId());
          taDto.setPositionName(passenger.getPosition().getName());
        }
      }

      dto.getApprovers().add(taDto);
    }

    return dto;
  }

  @Override
  public JsonResult saveCustomerPosition(int enterpriseId, int userId, @NotNull CustomerPosition dto) {
    int status = 0;
    User user = userDao.getUserById(userId);

    if (dto.getMode() == 0) {
      if (dto.getName() == null || dto.getName().length() < 2) {
        return JsonResult.createJsonResult(-1, "级别名称是必需的");
      }

      if (dto.getPositionId() < 1) {
        return JsonResult.createJsonResult(-2, "级别ID是必需的");
      }

      try {
        status = enterpriseDao.saveCustomerPosition(enterpriseId, user.getUsername(), dto);
      } catch (RuntimeException ex) {
        return JsonResult.createJsonResult(-100, ex.getMessage());
      }
    } else if (dto.getMode() == 4){
      status = enterpriseDao.deleteCustomerPosition(enterpriseId, user.getUsername(), dto.getId());
    }

    return JsonResult.createJsonResult(status);
  }

  @Override
  public List<CustomerPositionDto> searchCustomerPositions(int enterpriseId, SearchCustomerCriteria sc) {
    List<CustomerPosition> positions = enterpriseDao.searchCustomerPositions(enterpriseId, sc);

    List<CustomerPositionDto> dtos = new ArrayList<>();

    for(CustomerPosition position: positions) {
      dtos.add(CustomerPositionDto.createdBy(position));
    }

    return dtos;
  }

  @Override
  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_DATA_ADMIN})
  public JsonResult generatePassengerLoginInfo(final int userId, final int psgId) {
    Passenger passenger = passengerDao.getById(psgId);
    User user = userDao.getUserById(userId);

    if (passenger.getEnterpriseId() != user.getEnterpriseId()) {
      throw new RuntimeException("Passenger is not existed.");
    }

    User psgUser = new User();
    psgUser.setUsername(User.getTemporaryUsername() + "_" + psgId);
    psgUser.setEmpname(passenger.getNameCn());

    Date defaultExpireDate = DateUtil.getCurDate();
    defaultExpireDate = DateUtil.addDays(defaultExpireDate, 10000);
    psgUser.setExpireDate(defaultExpireDate);

    psgUser.setCreateTime(DateUtil.getCurDate());
    psgUser.setMd5Password(VerifyCodeUtil.MD5(User.DEFAULT_PASSWORD));
    psgUser.setUserType(User.USER_TYPE_ENT); // 默认为企业客户

    psgUser.setStatus(0); // 新建用户默认为停用状态

    psgUser.setParentEnterprise(user.getEnterpriseId());
    Enterprise psgEnterprise = new Enterprise();
    psgEnterprise.setId(passenger.getCustomer().getCustomerEnterpriseId());
    psgUser.setEnterprise(psgEnterprise);
    psgUser.setPassengerId(passenger.getId());

    try {
      int retCode = userDao.createPassengerUser(user, passenger, psgUser);
      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Override
  @Secured(RoleInfo.ROLE_ADMIN)
  public JsonResult saveApiProductSupplier(int enterpriseId, int productType, int supplierId) {
    return JsonResult.createJsonResult(enterpriseDao.saveApiProductSupplier(enterpriseId, productType, supplierId));
  }

  @Override
  public List<ProductDefaultSupplier> searchApiProductSupplier(int enterpriseId) {
    return enterpriseDao.searchApiProductSupplier(enterpriseId);
  }

  @Override
  public JsonResult deleteApiProductSupplier(int enterpriseId, int id) {
    return JsonResult.createJsonResult(enterpriseDao.deleteApiProductSupplier(enterpriseId, id));
  }

  @Override
  public JsonResult importPassengersByExcel(final int enterpriseId, final String username, final String fileName, final int customerId) {
    List<PassengerDto> list = new ArrayList<>();

    try {
      File target = new File(fileName);
      FileInputStream fi = new FileInputStream(target);
      Workbook wb = create(fi);

      generatePassengersFromExcel(enterpriseId, list, wb);
    } catch (Exception ex) {
      ex.printStackTrace();
      logger.error(ex.getMessage());
      return JsonResult.createJsonResult(-1, ex.getMessage());
    }

    if (list.isEmpty()) {
      return JsonResult.createJsonResult(-1, "没有数据");
    }

    //校验数据
    Customer customer = customerDao.getCustomerById(customerId);
    if (customer == null) {
      return JsonResult.createJsonResult(-1, "无此客户");
    }

    List<Passenger> passengers = new ArrayList<>();
    for(PassengerDto dto: list) {
      Passenger passenger = PassengerDto.convertTo(dto, enterpriseId);
      passengers.add(passenger);

      passenger.setCustomer(customer);

      //校验部门和职位等级是否存在
      if (dto.getDepartment() != null) {
        String deptName = dto.getDepartment().getName();
        CustomerDepartment cd = enterpriseDao.getCustomerDepartmentByDeptName(enterpriseId, customerId, deptName);
        if (cd == null) {
          return JsonResult.createJsonResult(-1, "部门(" + deptName + ")不存在。");
        } else {
          CustomerDepartment department = new CustomerDepartment();
          department.setId(cd.getId());
          passenger.setDepartment(department);
        }
      }
      if (dto.getPosition() != null) {
        String positionName = dto.getPosition().getName();
        CustomerPosition cp = enterpriseDao.getCustomerPositionByName(enterpriseId, customerId, positionName);
        if (cp == null) {
          return JsonResult.createJsonResult(-1, "职级(" + positionName + ")不存在。");
        } else {
          CustomerPosition position = new CustomerPosition();
          position.setId(position.getId());
          passenger.setPosition(position);
        }

      }
    }

    int retCode = enterpriseDao.savePassengers(passengers);

    return JsonResult.createJsonResult(retCode);
  }

  @Override
  public void splitPassengerEnglishName(final int ownerId, String agentName) {
    List<Passenger> passengers = passengerDao.searchPsgInfoFirstNameIsNull(ownerId, 5000);
    for(Passenger psg: passengers) {
      int intPos = psg.getNameEn().indexOf("/");
      if (intPos < 1) {
        continue;
      }

      final String firstName = psg.getNameEn().substring(0, intPos);
      final String lastName = psg.getNameEn().substring(intPos+1);

      passengerDao.updatePassengerFirstName(ownerId, agentName, psg.getId(), firstName, lastName);
    }
  }

  @Override
  public List<GroupCustomerService> searchCustomerServiceGroups(int enterpriseId) {
    return enterpriseDao.searchCustomerServiceGroups(enterpriseId);
  }

  @Override
  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_DATA_ADMIN})
  public JsonResult createOrUpdateCustomerServiceGroup(int enterpriseId, String username, int id, String code, String name) {
    if (code == null || name == null) {
      return JsonResult.createJsonResult(-1, "代码和名称都不能为空");
    }

    if (code.trim().length() == 0 || name.trim().length() == 0) {
      return JsonResult.createJsonResult(-1, "代码和名称都不能为空");
    }

    try {
      int retCode = enterpriseDao.createOrUpdateCustomerServiceGroup(enterpriseId, username, id, code, name);

      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_DATA_ADMIN})
  @Override
  public JsonResult updateCustomerGroup(int enterpriseId, String username, int customerId, int groupId) {
    try {
      int retCode = enterpriseDao.updateCustomerGroup(enterpriseId, username, customerId, groupId);
      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_DATA_ADMIN})
  @Override
  public JsonResult deleteCustomerGroup(int enterpriseId, String username, int customerId) {
    try {
      int retCode = enterpriseDao.deleteCustomerGroup(enterpriseId, username, customerId);
      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_DATA_ADMIN})
  @Override
  public JsonResult updateRepresentativeGroup(int enterpriseId, String username, int userId, int groupId) {
    try {
      int retCode = enterpriseDao.updateRepresentativeGroup(enterpriseId, username, userId, groupId);
      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_DATA_ADMIN})
  @Override
  public JsonResult deleteRepresentativeGroup(int enterpriseId, String username, int userId) {
    try {
      int retCode = enterpriseDao.deleteRepresentativeGroup(enterpriseId, username, userId);
      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Override
  public List<CustomerServiceTemplateDto> searchCustomerServiceTemplates(int enterpriseId) {
    List<CustomerServiceTemplate> templates = enterpriseDao.searchCustomerServiceTemplates(enterpriseId);
    List<CustomerServiceTemplateDto> dtos = new ArrayList<>();
    for(CustomerServiceTemplate tpl: templates) {
      dtos.add(CustomerServiceTemplateDto.createBy(tpl));
    }
    return dtos;
  }

  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_DATA_ADMIN})
  @Override
  public JsonResult createOrUpdateCustomerServiceTemplate(int enterpriseId, String username, CustomerServiceTemplate tpl) {
    try {
      if (tpl.getTemplateCode() == null
              || tpl.getTemplateCode().trim().length() == 0
              || tpl.getTemplateName() == null
              || tpl.getTemplateName().trim().length() == 0
      ) {
        return JsonResult.createJsonResult(-1, "模板代码和名称必填");
      }
      int retCode = enterpriseDao.createOrUpdateCustomerServiceTemplate(enterpriseId, username, tpl);
      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Override
  public CustomerServiceTemplateDto getCustomerServiceTemplateById(int enterpriseId, String username, int id) {
    CustomerServiceTemplate tpl = enterpriseDao.getCustomerServiceTemplateById(enterpriseId, id);
    if (tpl == null) {
      return null;
    }

    CustomerServiceTemplateDto dto = CustomerServiceTemplateDto.createBy(tpl);

    //获取机票的特定规则
    List<CustomerServiceFlightRule> flightRules = enterpriseDao.searchCustomerServiceFlightRules(enterpriseId, dto.getTemplateCode());
    for(CustomerServiceFlightRule flightRule: flightRules) {
      CustomerServiceFlightRuleDto ruleDto = CustomerServiceFlightRuleDto.createBy(flightRule);
      dto.getFlightRules().add(ruleDto);
    }

    return dto;
  }

  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_DATA_ADMIN})
  @Override
  public JsonResult updateCustomerTemplate(int enterpriseId, String username, int customerId, int templateId, String templateCode) {
    try {
      int retCode = enterpriseDao.updateCustomerTemplate(enterpriseId, username, customerId, templateId, templateCode);
      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Override
  public Optional<CustomerServiceTemplateDto> searchServiceTemplateByCustomer(int enterpriseId, int customerId) {
    CustomerServiceTemplate tpl =  enterpriseDao.searchServiceTemplateByCustomer(enterpriseId, customerId);
    return tpl == null ? Optional.empty(): Optional.of(CustomerServiceTemplateDto.createBy(tpl));
  }

  @Override
  public Optional<BlobService> createBlobService(final int enterpriseId) {
    String accountName = doGetEntCfg(enterpriseId, API_AZURE_STORAGE_ACCOUNT_NAME);
    if (StringUtils.isBlank(accountName)) {
      //使用通用的
      accountName = doGetEntCfg(0, API_AZURE_STORAGE_ACCOUNT_NAME);
    }

    String accountKey = doGetEntCfg(enterpriseId, API_AZURE_STORAGE_ACCOUNT_KEY);
    if (StringUtils.isBlank(accountKey)) {
      //使用通用的
      accountKey = doGetEntCfg(0, API_AZURE_STORAGE_ACCOUNT_KEY);
    }

    if(StringUtils.isEmpty(accountName) || StringUtils.isEmpty(accountKey)) {
      return Optional.empty();
    }

    BlobServiceImpl impl = new BlobServiceImpl(accountName, accountKey, "core.chinacloudapi.cn");

    return Optional.of(impl);
  }

  @Override
  public String getBlobStorageContainerName(int enterpriseId) {
    String name = doGetEntCfg(enterpriseId, API_AZURE_STORAGE_CONTAINER_NAME);
    if (StringUtils.isBlank(name)) {
      name = doGetEntCfg(0, API_AZURE_STORAGE_CONTAINER_NAME);
    }
    return name;
  }

  @Override
  public int saveFileNameMapping(int enterpriseId, String username, String fileName, String blobName, String contentType, long fileSize) {
    return enterpriseDao.saveBlobMapping(enterpriseId, username, fileName, blobName, contentType, fileSize);
  }

  @Override
  public List<TmsTask> searchTasks(int enterpriseId, CommonSearchCriteria sc) {
    return enterpriseDao.searchTasks(enterpriseId, sc);
  }

  @Override
  public void createDailyAuditTask(int enterpriseId, String username) {
    TmsTask tmsTask = new TmsTask();
    tmsTask.setEnterpriseId(enterpriseId);
    tmsTask.setTaskType(TMS_TASK_TYPE_DAILY_AUDIT);
    tmsTask.setCreateDate(DateUtil.getCurDate());
    tmsTask.setTitle("日账单审核");
    tmsTask.setContent("每天审核当天生成的账单的成本和收入");

    List<TmsTask> list = enterpriseDao.searchTasks(enterpriseId, TMS_TASK_TYPE_DAILY_AUDIT, DateUtil.getCurDate());
    if (list.isEmpty()) {
      userDao.createTmsTask(tmsTask);
    }
  }

  @Override
  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_CASHIER})
  public JsonResult finishDailyTask(final int enterpriseId, final String username, final int taskId) {
    int retCode = enterpriseDao.finishDailyTask(enterpriseId, username, taskId);

    if (retCode > 0) {
      threadPool.execute(() ->  doAutoExportAuditedBill(enterpriseId, username, taskId));
    }

    return JsonResult.createJsonResult(retCode);
  }

  @Override
  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_CASHIER})
  public JsonResult resendDailyTask(int enterpriseId, String username, int taskId) {
    TmsTask tt = userDao.getTmsTaskById(taskId);

    if (tt.getStatus() != 1 || tt.getDoneDate() == null) {
      return JsonResult.createJsonResult(-1, "任务未完成");
    }

    if (tt.getSendFileTime() == null && DateUtil.getPastMinutes(tt.getDoneDate()) <= 5) {
      return JsonResult.createJsonResult(-2, "任务完成5分钟后再试。");
    } else if (tt.getSendFileTime() != null && DateUtil.getPastMinutes(tt.getSendFileTime()) <= 15) {
      return JsonResult.createJsonResult(-3, "重新发送文件需要至少间隔15分钟。");
    }

    threadPool.execute(() -> doAutoExportAuditedBill(enterpriseId, username, taskId));

    return JsonResult.createJsonResult(1, "后台处理中");
  }

  @Override
  public List<ReportTemplateInfo> searchReportTemplates(int enterpriseId) {
    return enterpriseDao.searchReportTemplates(enterpriseId);
  }

  @Override
  public JsonResult updateCustomerReportTemplate(int enterpriseId, String username, int customerId, int templateId) {
    return JsonResult.createJsonResult(enterpriseDao.updateCustomerReportTemplate(enterpriseId, username, customerId, templateId));
  }

  @Override
  public JsonResult createOrUpdateCustomerServiceFlightRule(int enterpriseId, String username, int templateId, CustomerServiceFlightRule fltRule) {
    CustomerServiceTemplateDto tpl = this.getCustomerServiceTemplateById(enterpriseId, username, templateId);
    if (tpl == null) {
      return JsonResult.createJsonResult(-1, "指定的模板不存在");
    }

    if (StringUtils.trimToEmpty(fltRule.getCarrier()).length() == 0) {
      return JsonResult.createJsonResult(-2, "航司代码不能为空");
    }

    if (StringUtils.trimToEmpty(fltRule.getSubclasses()).length() == 0) {
      return JsonResult.createJsonResult(-2, "舱位代码不能为空");
    }

    int retCode = enterpriseDao.createOrUpdateCustomerServiceFlightRule(enterpriseId, username, tpl.getTemplateCode(), fltRule);

    return JsonResult.createJsonResult(retCode);
  }

  @Override
  public JsonResult savePassengerFlightKeyCustomerPolicy(int enterpriseId, String username, int[] psgIds, int[] policyIds) {
    if (psgIds.length == 0 || policyIds.length == 0) {
      return JsonResult.createJsonResult(-1, "乘机人和政策都需要至少一个");
    }

    int count = 0;
    for(int psgId: psgIds) {
      for(int policyId: policyIds) {
        try {
          int retCode = passengerDao.savePassenger2FlightKeyCustomerPolicy(enterpriseId, username, psgId, policyId);
          if (retCode > 0) {
            count++;
          }
        } catch (RuntimeException ex) {
          logger.error(ex.getMessage());
        }
      }
    }

    if (count == 0) {
      return JsonResult.createJsonResult(0, "保存数为0.");
    } else {
      return JsonResult.createJsonResult(count, "保存了" + count + "条记录.");
    }
  }

  @Override
  public JsonResult removePassengerFlightPolicy(int enterpriseId, String username, int psgId, int policyId) {
    try {
      int retCode = passengerDao.removePassengerFlightPolicy(enterpriseId, username, psgId, policyId);
      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Override
  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_DATA_ADMIN})
  public JsonResult saveCustomerAvCountInfo(final int enterpriseId, final int customerId,
                                            final int maxTotal, final int maxMonthly) {
    if (maxTotal > 0 && maxTotal <= maxMonthly) {
      return JsonResult.createJsonResult(-1, "总次数必须大于月最大次数");
    }

    Customer c = customerDao.getCustomerById(customerId);
    if (c.getCustomerEnterpriseId() > 0) {
      final int ceid = c.getCustomerEnterpriseId();
      enterpriseDao.setEnterpriseConfig(ceid, CUSTOMER_AV_MAX_TOTAL, maxTotal + "");
      enterpriseDao.setEnterpriseConfig(ceid, CUSTOMER_AV_MAX_MONTHLY, maxMonthly + "");
      return JsonResult.createJsonResult(1);
    } else {
      return JsonResult.createJsonResult(-2, "此用户暂时无法设置航班查询控制");
    }
  }

  @Override
  public void updateFlightSearchStat(FlightSearchStatDto dto) {
    final int ownerId = this.getOwnerId();
    final int enterpriseId = dto.getEnterpriseId();
    if (ownerId == 0 || ownerId != dto.getOwnerId() || enterpriseId < 1) {
      return;
    }

    //判断是否属于ownerId的下属客户
    Enterprise enterprise = enterpriseDao.getEnterpriseById(enterpriseId);
    if (enterprise == null || enterprise.getParentEnterprise() != ownerId) {
      return;
    }

    final int usedCount = this.doGetEntCfg(enterpriseId, CUSTOMER_AV_USED_MONTHLY, 0);
    if (usedCount == dto.getUsedCount()) {
      return;
    }

    final int maxCount = this.doGetEntCfg(enterpriseId, CUSTOMER_AV_MAX_MONTHLY, 100);
    if ((maxCount - usedCount) < 10) {
      doSendAlert(ownerId, enterprise.getName() + " 本月可用航班查询次数少于10次了, 请及时调整.", null, EntDepartment.DEPT_ADMINISTRATOR);
    }

    enterpriseDao.setEnterpriseConfig(enterpriseId, CUSTOMER_AV_USED_MONTHLY, dto.getUsedCount() + "");
  }

  @Override
  public WeixinServiceConfig searchWeixinServiceConfig(int enterpriseId) {
    return weixinService.getWeixinServiceConfig(enterpriseId);
  }

  @Override
  @Secured(RoleInfo.ROLE_ADMIN)
  public JsonResult updateWeixinServiceConfig(int enterpriseId, String username, String appId, String appSecret, String token, String encodingKey) {
    WeixinServiceConfig config = new WeixinServiceConfig();
    config.setAppId(appId);
    config.setAppSecret(appSecret);
    config.setToken(token);
    config.setEncodingKey(encodingKey);

    int retCode = weixinService.saveWeixinServiceConfig(enterpriseId, config);


    return JsonResult.createJsonResult(retCode);
  }

  @Override
  public JsonResult updateWorkWeixinConfig(int enterpriseId, String username, String corpId, int msgType, int agentId, String agentSecret, String token, String encodingKey) {
    WeixinEntConfig config = new WeixinEntConfig();

    config.setCorpId(corpId);
    config.setMsgType(msgType);
    config.setAgentId(agentId);
    config.setSecret(agentSecret);
    config.setToken(token);
    config.setEncodingAESKey(encodingKey);

    int retCode = workWeixinService.saveWorkWeixinConfig(enterpriseId, config);


    return JsonResult.createJsonResult(retCode);
  }

  @Override
  public List<WeixinEntConfig> searchWorkWeixinConfig(int enterpriseId) {
    return workWeixinService.searchWorkWeixinConfigs(enterpriseId);
  }

  @Override
  public List<TmsWwAppChat> searchWwAppChats(int enterpriseId) {
    return enterpriseDao.searchWwAppChats(enterpriseId);
  }

  @Override
  public JsonResult createWwAppChat(int enterpriseId, TmsWwAppChat appChat) {
    appChat.setEnterpriseId(enterpriseId);
    int retCode = enterpriseDao.createWwAppChat(appChat);
    return JsonResult.createJsonResult(retCode);
  }

  @Override
  public List<TmsWwUser> searchWwUsers(int enterpriseId) {
    return  enterpriseDao.searchWwUsers(enterpriseId);
  }

  @Override
  public TmsWwAppChat searchWwAppChat(int enterpriseId, String chatId) {
    var rs = wwService.getAppChat(enterpriseId, chatId);
    if (rs.getErrcode() == 0) {
      TmsWwAppChat o = enterpriseDao.searchWwAppChat(enterpriseId, chatId);
      if (o != null) {
        o.setName(rs.getChatInfo().getName());
        enterpriseDao.updateWwAppChat(o);
      }

      return o;
    }
    return null;
  }

  @Override
  public TmsWwAppChat searchWwAppChatByType(int enterpriseId, String qtype) {
    return enterpriseDao.searchWwAppChatByType(enterpriseId, qtype);
  }

  @Override
  public void sendAlertMessage(int enterpriseId, String content) {
    doSendAlert(enterpriseId, content, "Dai", 0);
  }

  @Override
  public JsonResult updateAlipayConfig(int enterpriseId, String username, String mainAccount, String appId, String privateKey, String alipayPublicKey, String returnUrl, String notifyUrl) {
    if (StringUtils.isBlank(mainAccount) || StringUtils.isBlank(appId)) {
      return JsonResult.createJsonResult(-1, "主账号、应用id不能为空");
    }
    int retCode = enterpriseDao.updateAlipayConfig(enterpriseId, username,
            mainAccount, appId, privateKey, alipayPublicKey, returnUrl, notifyUrl);

    return JsonResult.createJsonResult(retCode);
  }

  @Override
  public List<EntAlipayCfgDto> searchAlipayConfigs(int enterpriseId) {
    var list = enterpriseDao.searchAlipayConfigs(enterpriseId);

    var dtoList = new ArrayList<EntAlipayCfgDto>();
    for(var cfg: list) {
      var dto = new EntAlipayCfgDto();
      BeanUtils.copyProperties(cfg, dto);

      dto.setPrivateKey("*");
      dto.setAlipayPublicKey("*");

      dtoList.add(dto);
    }

    return dtoList;
  }

  @Override
  public JsonResult deleteAlipayConfig(int enterpriseId, String username, int id) {
    int retCode = enterpriseDao.deleteAlipayConfig(enterpriseId, username, id);

    return JsonResult.createJsonResult(retCode);
  }

  @Override
  public List<TmsSupplierDto> searchTmsSuppliers(int enterpriseId) {
    var list = new ArrayList<TmsSupplierDto>();
    var cfgs = enterpriseDao.searchEntEotmsConfig(0);
    for(var cfg: cfgs) {
      int supplierId = cfg.getSupplierId();
      Supplier supplier = enterpriseDao.getSupplierById(supplierId);
      if (supplier == null) {
        continue;
      }
      list.add(TmsSupplierDto.create(supplier.getId(), "(共用)" + supplier.getName()));
    }

    cfgs = enterpriseDao.searchEntEotmsConfig(enterpriseId);
    for(var cfg: cfgs) {
      int supplierId = cfg.getSupplierId();
      Supplier supplier = enterpriseDao.getSupplierById(supplierId);
      if (supplier == null) {
        continue;
      }
      list.add(TmsSupplierDto.create(supplier.getId(), supplier.getName()));
    }

    return list;
  }


  private void generatePassengersFromExcel(final int enterpriseId, List<PassengerDto> list,
                                            Workbook wb) {
    Sheet sheet = wb.getSheetAt(0);
    final int rowNum = sheet.getLastRowNum() + 1;

    int dataCount = 0;
    for (int i = 1; i < rowNum; i++) {
      Row row = sheet.getRow(i);
      dataCount++;

      PassengerDto passengerDto = new PassengerDto();
      passengerDto.setEnterpriseId(enterpriseId);

      passengerDto.setNameCn(getStringCellValue(row.getCell(0)));
      passengerDto.setFirstName(getStringCellValue(row.getCell(1)));
      passengerDto.setLastName(getStringCellValue(row.getCell(2)));
      passengerDto.setNameEn(getStringCellValue(row.getCell(3)));

      String temp = getStringCellValue(row.getCell(4));
      if ("男".equalsIgnoreCase(temp)) {
        passengerDto.setGender(1);
      } else if ("女".equalsIgnoreCase(temp)) {
        passengerDto.setGender(2);
      }

      try {
        temp = getStringCellValue(row.getCell(5));
        passengerDto.setBirthday(DateUtil.convertToDate(temp, DATE_YYYY_MM_DD));
      } catch (Exception ex) {
        logger.warn(ex.getMessage());
      }

      temp = getStringCellValue(row.getCell(6));
      passengerDto.setMobile(temp);

      passengerDto.setPhone(getStringCellValue(row.getCell(7)));
      passengerDto.setEmail(getStringCellValue(row.getCell(8)));

      temp = getStringCellValue(row.getCell(9));
      if (temp != null && temp.length() > 0) {
        CustomerDepartmentDto departmentDto = new CustomerDepartmentDto();
        departmentDto.setName(temp);
        passengerDto.setDepartment(departmentDto);
      }

      temp = getStringCellValue(row.getCell(10));
      if (temp != null && temp.length() > 0) {
        CustomerPositionDto positionDto = new CustomerPositionDto();
        positionDto.setName(temp);
        passengerDto.setPosition(positionDto);
      }

      //身份证号码
      temp = getStringCellValue(row.getCell(11));
      if (temp != null && temp.length() > 0) {
        PassengerIdInfoDto dto = new PassengerIdInfoDto();
        dto.setIdType(ID_TYPE_NI);
        dto.setIdNo(temp);
        passengerDto.getIdInfos().add(dto);
      }

      //护照
      temp = getStringCellValue(row.getCell(12));
      if (temp != null && temp.length() > 0) {
        PassengerIdInfoDto dto = new PassengerIdInfoDto();
        dto.setIdType(ID_TYPE_PASSPORT);
        dto.setIdNo(temp);
        passengerDto.getIdInfos().add(dto);

        temp = getStringCellValue(row.getCell(13));
        try {
          dto.setIdValidDate(DateUtil.convertToDate(temp, DATE_YYYY_MM_DD));
        } catch (Exception ex) {
          logger.error(ex.getMessage());
        }

        temp = getStringCellValue(row.getCell(14));
        dto.setIdIssueNation(temp);
      }

      //喜好
      temp = getStringCellValue(row.getCell(15));
      passengerDto.setHobby(temp);


      //备注
      temp = getStringCellValue(row.getCell(16));
      passengerDto.setRemark(temp);

      list.add(passengerDto);
    }

    if (list.size() != dataCount) {
      list.clear();
    }
  }



  @Override
  @Secured(RoleInfo.ROLE_ADMIN)
  public JsonResult setBspSupplier(int enterpriseId, int supplierId, int bspType) {
    return JsonResult.createJsonResult(enterpriseDao.setBspSupplier(enterpriseId, supplierId, bspType));
  }


}
